2014-09-19 2 views
-5

я проходил через рамку правила вопросов и все, а затем получил фрагмент кода, ниже:Каким будет его выход и почему?

#include <stdio.h> 
int main() 
{ 
    int x = 1, y = 2, z = 3; 
    printf(" x = %d, y = %d, z = %d \n", x, y, z); 
    { 
     int x = 10; 
     float y = 20; 
     printf(" x = %d, y = %f, z = %d \n", x, y, z); 
     { 
      int z = 100; 
      printf(" x = %d, y = %f, z = %d \n", x, y, z); 
     } 
    } 
    return 0; 
} 

Если изменить последнюю печать на:

printf("x = %d, y = %d, z = %d \n", x, y, z); 

я получаю следующий вывод, который я не понимаю: (Ideone link)

x = 10, y = 0, z = 1077149696 

Таким образом, могли бы вы объяснить, почему г печати это значение?

+1

Мое предположение, потому что '' printf' использует vargs', и ожидать, что '% d' для 'float y', он считывает первые 4 байта float, который равен 0, и оставляет последние 4 байта в следующем'% d', который равен z, поэтому z имеет неопределенное значение, напечатанное. – texasbruce

+2

Этот код не идентичен примеру в ideone. – Galik

+0

-1 Этот код полностью работает и не совпадает с кодом в идеоне, из которого вы взяли результаты. Код ideone имеет ошибку. – Galik

ответ

9

x, y и z разрешены для большинства локальных определений.

При использовании неправильного спецификатора printf% поведение не определено.

y is float, но вы используете% d для его печати (в более поздней строке).

printf использует varargs и как только вы повреждаете стек, используя неправильный спецификатор (% d вместо% f в этом случае), стек поврежден, а некорректная интерпретация данных стека (при некорректном смещении) вызовет много болезненных сюрпризов.

Декодирование Этот UB

Это то, что может происходить на вашей машине (Одно из возможных объяснений). Из-за default argument promotion битовая диаграмма (в шестнадцатеричной форме) 0x4034000000000000 выталкивается в стек для 20.0f. Размер int на вашем компьютере с мини-байтом составляет 4 байта. Когда вы печатаете float как int, ваш компьютер 0x00000000 расходуется и интерпретируется как int, который печатает сначала 0, позже %d потребляет 0x40340000, интерпретирует его как int и распечатывает 1077149696. Финал 100 (0x00000064) оставлен в стеке без потерь и возвращает printf.

Но никогда не полагайтесь на это и всегда пишите код, для которого поведение четко определено.

+1

Дорогой Доводчик, написал ли я что-то очень неправильное? –

+1

Думаю, что, по крайней мере, глядя на код в вопросе, строки формата 'printf' выглядят ОК. Вы действительно ссылаетесь на код в ссылке? BTW вот код из вопроса о ideone: http://ideone.com/k6TCB7 – juanchopanza

+1

Код сразу после строки 'Я думал, что, если самый внутренний шрифт был следующим:' в вопросе. –

0

z = 1077149696
Использование% d для печати значений поплавков является неопределенным поведением.
Используйте «% F» вместо

  1. Все переменные, которые вы использовали имеют тип хранения «Auto» или «Автоматический».
  2. Объем автоматической переменной лежит внутри блока, в котором он объявлен.
  3. Если есть вложенные блоки, то переменная, объявленная в самом удаленном блоке, будет видна всем остальным блокам.
  4. Если в блоке объявлена ​​переменная, которая совпадает с объявленной в внешних блоках, тогда она будет перезаписывать внешнюю переменную «в своем блоке», то есть (локально).

Подводя итог: Автоматические переменные являются локальными для блока, в котором они объявлены.

2

@ mohit-jain является правильным.

Использование спецификатора неправильного формата дает неверную интерпретацию параметров в стеке, что приводит к неопределенному и специфичному для компилятора поведению.

Обратите внимание, что на современном компилятором, как GCC или звоном, он будет жаловаться, что ваша спецификация формата является неправильным:

$ clang test.c 
test.c:12:54: warning: format specifies type 'int' but the argument has type 'float' 
     [-Wformat] 
      printf(" x = %d, y = %d, z = %d \n", x, y, z); 
            ~~    ^
            %f 
1 warning generated. 
Смежные вопросы