2014-04-25 11 views
6

Я пытаюсь понять фрейм стека в C, поэтому я написал простой C-код для анализа фрейма стека.Понимание стековых фреймов в C

  • Прежде всего fun1() возвращает адрес локальной переменной, которая инициализируется 10 до PTR, что приводит к предупреждению, но это нормально ... Если я теперь напечатает значение * PTR печатает 10, даже это прекрасно ...

  • Следующий fun2() возвращает адрес локальной переменной, которая даже не инициализирована, и если я попытаюсь напечатать значение * ptr, теперь он печатает 10 независимо от того, возвращая адрес a или b ...

  • Чтобы понять, что на самом деле происходит здесь, я использовал gdb. Использование GDB, я начал шаг за шагом отладки и когда я дошел до линии «возвращение &» в fun2(), я пытался напечатать адрес б, печать & б но напечатанное Не может введите адрес «b», который не является значением lvalue.

Я не понимаю, когда я пытаюсь напечатать адрес, печати & печатает абсолютно нормально, то почему бы не обратиться Ь. * Почему нет b значения l, когда оно есть?

# include <stdio.h> 

int * fun1() { 
    int a = 10; 
    return &a; 
} 

int * fun2() 
{ 
    int a; 
    int b; 
    return &a;   // return &b; 
} 

int main() 
{ 
    int *ptr; 
    ptr = fun1(); 
    ptr = fun2(); 
    printf ("*ptr = %d, fun2() called...\n", *ptr); 
    return 0; 
} 
+0

http://stackoverflow.com/a/18479996/1814023 –

+1

вы вызываете неопределенное поведение. Нет никакой гарантии, что результаты будут иметь какой-либо смысл или будут делать то, что вы ожидаете от макета стека. Стандартная гипербола заключается в том, что программе разрешено делать [демоны] (http://www.catb.org/jargon/html/N/nasal-demons.html) вылетающим из носа. – user2357112

+2

Вам повезло, что печать '* ptr' печатает 10; это, безусловно, не гарантируется (вы вызываете неопределенное поведение). Но вы действительно должны показать весь код. В коде компилятор, вероятно, сбросил 'b' как неиспользуемую переменную, поэтому у него нет местоположения, поэтому вы не можете взять его адрес. Используйте 'b' в коде, так или иначе, и вы сможете его распечатать. И, пожалуйста, не сообщайте «что-то вроде»; быть точным и сообщать точно, что говорит отладчик. –

ответ

3

Компилятор оптимизирует код в fun2.

Если вы вернетесь &a, он оптимизирован int b;. Если вы вернетесь &b, он будет оптимизирован int a;. Если вы добавите несколько фиктивных вычислений, вы увидите, что адреса возвращаемых значений будут разными.

int * fun2() 
{ 
    int a; 
    int b; 
    int* p = &a; 
    p = &b; 
    return p; 
} 

Изменить main для печати возвращаемых значений fun1 и fun2.

int main() 
{ 
    int *ptr; 
    ptr = fun1(); 
    printf ("ptr = %p, fun1() called...\n", ptr); 
    ptr = fun2(); 
    printf ("ptr = %p, fun2() called...\n", ptr); 
    printf ("*ptr = %d, fun2() called...\n", *ptr); 
    return 0; 
} 

Когда я запускаю этот код, я получаю следующий пример вывода:

 
ptr = 0x7ffff98c70ec, fun1() called... 
ptr = 0x7ffff98c70e4, fun2() called... 
*ptr = 32749, fun2() called... 
+0

Ya that's true, если я инициализирую b, он возвращает мусор, но то же самое должно быть истинным, если я скомпилирую с -00 уровнем оптимизации. Но когда я скомпилирую его с уровнем оптимизации -O0, результат будет таким же снова, т.е. 10 – Adarsh

0

Он компилирует для меня просто отлично, при возврате адреса в б. Но вы не должны возвращать адрес локальной переменной. Check out this link.

+0

Я верю, но моя цель здесь не в достижении чего-либо из этого кода, а в том, чтобы понять, как адрес переменной стека, используемый в одной функции, может быть повторно использован в другой функции ... Спасибо за помощь ... – Adarsh