2009-10-07 2 views
0

, когда я попытался запустить скомпилировать и выполнить это заявление в простой файл Си:Каков результат этой программы?

main(){ printf("%d");} 

на HP это дает мне 64 и AIX его дает мне 804359524.

Может кто-нибудь сказать мне, что это это поведение.

+0

Какое заявление? –

+1

RTFM. [Требуется xtra chars] – spender

ответ

21

Я полагаю, вы имели в виду:

int main() 
{ 
    printf("%d"); 
} 

В таком случае, Е(), читает Int (в соответствии с указаниями спецификатор формата% D) из стека. Поскольку вы не указали один, он просто читает все, что находится в стеке, и используя это. Следовательно, ваш наблюдаемый псевдослучайный выход.

Вместо этого попробуйте:

int main() 
{ 
    printf("%d", 10101); 
} 

HTH

2

Код подвергается неопределенному поведению. В других системах он может печатать «Переполнение стека» (серьезно!). % d сообщает библиотеке CRT, что вы предоставите целое число, но вы этого не сделаете.

+0

Я не думаю, что вы когда-нибудь получите переполнение стека в этом коде - стек не растет. – Skizz

+0

Триггер для переполнения стека, как правило, является доступом к памяти на странице защиты стека. printf() может инициировать этот доступ, когда ему не удается прочитать целое число% d, и вместо этого обращается к странице защиты. И поскольку это не письмо, вы не можете его решить, добавив еще одну страницу. Для ОС рекомендуется печатать «переполнение стека» всякий раз, когда есть какая-либо ошибка в нарушении безопасности стека; он будет на 99% прав – MSalters

+1

Я думаю, что в этом случае напечатанное значение будет либо адресом возврата из функции printf, либо регистровым значением, либо, возможно, что-то из основного стекового кадра, в зависимости от реализации компилятора и ОС работает. Я всегда думал, что «переполнение стека» было тогда, когда в стеке не хватило памяти при попытке сохранить данные в стеке, никогда не при чтении данных. – Skizz

0

Я предполагаю, что вы собираете

main(){ printf("%d");} 

Это будет выбрать случайное значение из текущего стека. Попробуйте это:

main() { 
    printf("%d", 0); 
    printf("%d"); 
} 

Теперь второй printf() всегда будет печатать 0, так как он получает тот же стек в качестве первого вызова.

[EDIT] Это не работает на x86 Linux с GCC 4.1.2. Вот сгенерированный код на ассемблере (использование gcc -S -o t.s t.c):

movl $0, %esi 
    movl $.LC0, %edi 
    movl $0, %eax 
    call printf 
    movl $.LC0, %edi 
    movl $0, %eax 
    call printf 

Как вы можете видеть, второй аргумент не помещается в стек, но прошел через %esi (который является регистром). Этот же регистр, вероятно, изменен в printf(), поэтому он теряет свою ценность. Damn optimizations;)

+0

Не удивил бы меня, если бы вы получили 1. printf возвращает количество потребляемых аргументов. Это возвращаемое значение может перезаписать стек. – MSalters

+0

Я сомневаюсь, что по двум причинам: a) На большинстве машин возвращаемое значение находится в регистре и b) оно перезапишет строку формата, если она была передана в стеке, если она не была сохранена в другом месте ABI , –

+0

Аарон, работающий с компилятором intel icc, дает предупреждение о втором printf и выходе 04204818 (0 и 4204818) – Glen

12

Это классический undefined behavior. Компилятор не проверяет, что вы предоставляете достаточно аргументов, чтобы они соответствовали вашей строке форматирования. Есть компиляторы, которые делают это (gcc is one), но у вас нет.

Код в printf() будет счастливо пошагово его заданного форматирования строки, и когда он попадает в «% г» он будет считывать один int -sized аргумент (обычно: из стека), не зная, что нет аргументов там для этого читать.

Независимо от того, какое значение происходит в стеке, печатается.

3

Некоторые компиляторы, такие как gcc, поймают этот тип общих проблем, если вы укажете достаточно высокий уровень предупреждения. Как это (составитель вам код, с -Wall - все предупреждения):

gcc -c -g -Wall -MMD -MP -MF build/Debug/Cygwin-Windows/newmain.o.d -o build/Debug/Cygwin-Windows/newmain.o newmain.c 
newmain.c: In function `main': 
newmain.c:16: warning: too few arguments for format 

Это один из около 998 хороших причин, чтобы всегда компилируются с высоким уровнем предупреждения, а также принимать предупреждающие сообщения всерьез.

Смежные вопросы