2016-01-04 15 views
5

Próbuję zrozumieć wskaźniki i natknąłem się na ten fragment kodu, a ilekroć go kompiluję i wykonuję, adres zmienia się. Czy jest to jakaś wartość śmieciowa, czy wskaźniki rzeczywiście mają pamięć przydzieloną w drodze?Czy adresy wskaźnikowe zmieniają się za każdym razem, gdy program jest wykonywany w C?

Mój wiersz polecenia:

[email protected]:~/Desktop/Learn_C$ ./Practice 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0xbf98fd64 

[email protected]:~/Desktop/Learn_C$ make Practice 
make: 'Practice' is up to date. 

[email protected]:~/Desktop/Learn_C$ ./Practice 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0xbfcce2a4 

[email protected]:~/Desktop/Learn_C$ ./Practice 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0xbfa25df4 

[email protected]:~/Desktop/Learn_C$ ./Practice 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0xbfecf104 

Mój kod C:

#include <stdio.h> 

int main() 
{ 
    int nNumber; 
    int *pPointer; 

    nNumber = 15; 
    pPointer = &nNumber; 

    printf("nNUmber is equal to : %d\n", nNumber); 

    *pPointer = 25; 

    printf("nNumber is equal to : %d\n", nNumber); 

    printf("%p\n", pPointer); 

    return 0; 
} 

Z góry dziękuję.

+4

Jest to ogólna funkcja zabezpieczeń: [Randomizacja układu przestrzeni adresowej] (https://en.wikipedia.org/wiki/Address_space_layout_randomization) –

+1

Dlaczego upadek. To jest uzasadnione pytanie. – alk

Odpowiedz

4

Reprezentacja lub co dokładnie stanowi wartość wskaźnika jest szczegółem implementacji. Norma C nie określa żadnych wymagań w tym zakresie. Nie ma gwarancji, że wartość będzie taka sama lub inna za każdym razem, gdy uruchomisz kod.

Tylko arytmetyczna wskaźnik między ważnymi wskaźnikami (np. Porównywanie dwóch wskaźników w obiekcie tablicy) jest definiowany przez standard C.

Nawiasem mówiąc, należy rzutować wskaźnik do void* wydrukować %p wymagane przez standard C:

printf("%p\n", (void*) pPointer); 

Jak zauważył w komentarzach, niektóre systemy operacyjne zrobić address space layout randamization. Linux robi to domyślnie. Dla kodu, pojawia się następujący komunikat o ASLR:

$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffde18ba7c 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fff981efe0c 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7ffdade6837c 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7ffced208b4c 

Gdybym wyłączyć go z:

echo 0 > /proc/sys/kernel/randomize_va_space 

następnie wyprowadza te same wartości:

$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 
$ ./a.out 
nNUmber is equal to : 15 
nNumber is equal to : 25 
0x7fffffffeaec 

Ale o ile Standard C dotyczy, nie ma absolutnie żadnej gwarancji na wartości.

1

Czy jest to wartość śmieciowa, czy wskaźniki rzeczywiście mają pamięć przydzieloną w drodze?

Ani. Wartość wskaźnika, którą drukujesz, jest inna, ponieważ adres wskazanego obiektu (nNumber) jest różny w każdym przebiegu programu lub ponieważ używany styl reprezentacji wskaźnika zapewnia różne reprezentacje dla tego samego adresu lub obu. W praktyce ta pierwsza jest znacznie bardziej prawdopodobna.

Adres nNumber jest funkcją miejsca, w którym program został załadowany do pamięci (wirtualnej) i nic nie wymaga, aby był spójny od uruchomienia do uruchomienia. Rzeczywiście, jak zauważa Jeff Mercado w komentarzach, istnieje mechanizm nazywany "Randomizacją układu przestrzeni adresowej", który, gdy jest wykorzystywany, celowo dobiera losowe adresy ładowania programów i bibliotek w celu poprawy bezpieczeństwa systemu. Jego użycie jest prawdopodobnym i dość prawdopodobnym wyjaśnieniem dla twojej obserwacji, ale w żadnym wypadku nie jest to jedyne możliwe.