Przeskok w adresowaniu pamieci - wytłumaczenie


(pain3hp) #1
int main(){

int *wsk1, *wsk2, *wsk3;

int a=3, b=5, c=7;

short int d = 10, e = 15;

short int *wsk4, *wsk5;

wsk1 = &a;

wsk4 = &d;

wsk2 = &b;

wsk3 = &c;

wsk5 = &e;


cout << "Wielkosc int: " << sizeof(int) << endl;

cout << "Wielkosc short: " << sizeof(short) << endl;


cout << "Adres a: " << wsk1 << endl;

cout << "Adres b: " << wsk2 << endl;

cout << "Adres c: " << wsk3 << endl;

cout << "Adres d: " << wsk4 << endl;

cout << "Adres e: " << wsk5 << endl;

return 0;

}

wynik:

Wielkosc int: 4

Wielkosc short: 2

Adres a: 0xbff791dc

Adres b: 0xbff791e0

Adres c: 0xbff791e4

Adres d: 0xbff791fc

Adres e: 0xbff791fe

patrząc na końcówki adresów

dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ef....

moje pierwsze pytanie brzmi gdzie siedzi zmienna b, w zakresie dd-e0 czy może e0-e3?

drugie pytanie to dlaczego shorty poszły dopiero od fc? a nie od e6 lub e8?


(Sawyer47) #2

Jeśli chodzi o to w jakim zakresie pamięci jest zmienna b, to e0 .. e4 (adres wskazuje początek, adres+rozmiar koniec)

Odpowiedź zależy od wielu czynników, nie napisałeś na jakim procesorze/systemie/kompilatorze kompilowałeś kod.

Ogólna odpowiedź jest prawdopodobnie taka, że kompilator zmienił kolejność zmiennych na stosie. Patrz http://stackoverflow.com/questions/2384 ... -variables

Między innymi:


(pain3hp) #3

Intel E8400

Ubuntu 12.04

g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

Copyright © 2011 Free Software Foundation, Inc.

A czy zmiana ich kolejności nie ma wpływu na czas dostępu do nich? Do której zmiennej teoretycznie jest najszybciej się dostać? Na logikę działania stosu powiedziałbym, że do ostatniego zarezerwowanego (najwiekszego) ale czy na pewno? Także zauważyłem, że jeżeli w miarę jawnie najpierw zadeklarowałem short d to adresy pozostają bez zmian, więc to kompilator je "przestawia", choć może ja coś źle robie bo nie do końca to wszystko rozumiem

int a=3;

short int d = 10;

int b=5, c=7;

Adres a: 0xbffa5d1c

Adres b: 0xbffa5d20

Adres c: 0xbffa5d24

Adres d: 0xbffa5d3c

Adres e: 0xbffa5d3e

-- Dodane 17.08.2012 (Pt) 10:16 --

więc pewnie do e3 albo od e1 skoro rozmiar jest 4


(Sawyer47) #4

Kompilator robi wiele rzeczy, żeby wyprodukować bardziej optymalny kod. Między innymi wyrównuje adresy zmiennych do danych wartości (wielokrotności iluś bajtów) - może to być wymagane przez procesor i inaczej kod by nie działał (ew. tylko pewne instrukcje mogą wymagać wyrównania adresów) albo nie jest to wymagane, ale może przyśpieszyć jakiś operacje. W efekcie mogą wystąpić nieużywane obszary pamięci, służące jedynie jako wyrównanie dla innych zmiennych. Zobacz http://en.wikipedia.org/wiki/Data_padding

Przestawianie zmiennych w pamięci ma na celu między innymi zmniejszyć dodatkowe zajęcie pamięci spowodowane przez wyrównywanie.

Jeśli można tak ułożyć zmienne, aby wszystkie ich adresy na stosie miały odpowiednie wartości to kompilator może to zrobić.

Nazwy obszarów pamięci - stos, sterta - nie mają związku z dostępem do zmiennych, a z alokacją pamięci do nich, więc sam dostęp w ramach obszaru jest jest jednakowy

Tak jak zacytowałem powyżej, kompilator może robić ze zmiennymi na stosie bardzo dużo, już zależy od procesora/systemu/kompilatora/opcji kompilatora.

Nie, jeśli adres kończy się na e0 i zmienna ma rozmiar 4 bajtów, to końcowy adres to e4.

adres początkowy .. adres końcowy

e0 .. e1 - pierwszy bajt

e1 .. e2 - drugi bajt

e2 .. e3 - trzeci bajt

e3 .. e4 - czwarty bajt

To miałem na myśli pisząc e0 .. e4


(Rolek0) #5

image_id: 4956

Każdy bajt zajmuje jedną komórkę pamięci. Wskaźnik wskazuje na pierwszy bajt zmiennej.

Nie licząc cache'u, swapu i innych bajerów, dostęp do każdej komórki pamięci trwa tyle samo.

Stos na x86 to nie jest jakaś magiczna struktura, tylko po prostu wyznaczony fragment pamięci. To, że są specjalne instrukcje do operowania stosem nie znaczy, że nie można go używać jak normalnej pamięci.