2010-10-01 14 views
4
int main() 
{ 
    int x=5,y=10,z=15; 
    printf("%d %d %d"); 
    return 0; 
} 

Выход: 15 10 5 // В Turbo C 4,5Каков результат следующего кода?

3 Garbage values in gcc compiler 

Мой учитель сказал мне, когда мы определим переменные как межд х = 5, у = 10, г = 15; они по умолчанию принимаются как автоматические типы и хранятся в стеке. Когда вы пытаетесь напечатать 3 целых значения без использования их имен по printf(), он будет печатать эти 3 значения в формате LIFO, как это делает компилятор Turbo C. Но то, что я думаю, когда мы определяем 3 целочисленные переменные, они могут не храниться в местах непрерывной памяти. Поэтому, когда я пытаюсь напечатать 3 целочисленных значения без использования их имен, компилятор напечатает три значения из верхней части stack.so на выходе появятся 3 значения мусора, как в gcc ..

+0

Итак, ваш вопрос ...? –

+2

Получите нового учителя. Если он говорит что-то другое, кроме «это неопределенное поведение, не делайте этого», он не знает, о чем говорит. – JeremyP

+0

@ Daniel Standage, что логически правильно? – Parikshita

ответ

10

Этот код просто показывает, что Turbo C беден при оптимизации кода и ставит все на стек, в то время как НКУ более агрессивен и сохраняет его в регистрах или выбрасывает ее все вместе, потому что эти три переменные не имеют никакой цели ,

В любом случае, вызов printf с шаблоном, который требует трех аргументов без предоставления этих аргументов, является ошибкой.

Update:

В качестве объяснения: Я предполагаю, что Е() всегда будет принимать аргумент из стека, так как это функция с переменным списком аргументов. Или кто-нибудь знает любое другое соглашение о вызове для таких функций, как printf()? Более того, я предполагаю, что нет необходимости вносить что-либо еще в стек, поскольку нет других переменных. Таким образом, этот ошибочный звонок printf напечатает все, что находится поверх стека, в main(). Но могут существовать и другие архитектуры и вызывать соглашения, в которых мои собеседования не выполняются.

+3

Учитывая, что printf является библиотечной функцией, я не вижу, как компилятор может выбрать способ передачи ему параметров. Вызывающая конвенция была выбрана, когда библиотека была скомпилирована и компилятор должен соответствовать. – torak

+0

Оптимизация не в вызове _printf() _, а в том, как сохраняются локальные переменные в _main() _. Проблематичный вызов _printf() _ просто показывает, что находится в стеке. – Codo

4

Это неопределенное поведение.

С оптимизирующим компилятором эти 3 значения могут быть оптимизированы, поскольку они не используются. Он будет печатать мусор.

0

В MingW-GCC: 3 значения для мусора.

В VC++ 2010: 0, 0 и значение мусора.

2

Если для формата недостаточно аргументов, поведение не определено.

3

Поведение не определено, что означает, что компилятор может свободно обрабатывать ситуацию так, как считает нужным. Что касается языкового стандарта, то как Turbo C, так и gcc делают «правильную» вещь.

+3

И программист, который написал код, не «делает« правильную вещь »! –

1

Ваш учитель ошибается, но не полностью.

Переменные, объявленные внутри функции, по умолчанию auto, а не static.

int foo(void) { 
    static int x; 
    int y; 
    auto int z; 

    /* ...other code... */ 
} 

Это означает, что в функции выше y является автоматической, так же, как г, даже если auto ключевое слово не используется в его заявлении. К слову, ключевое слово auto почти не используется.Многие программисты на языке C (и C) даже не знают, что auto - это ключевое слово, потому что оно используется так редко.

Быть переменной auto обычно означает, что переменная хранится в системном стеке программы или в регистрах или в некотором их сочетании. Он может находиться в разных местах в разное время во время выполнения функции, а локальные переменные, которые находятся в регистре, часто выталкиваются в стек при вызове другой функции. Некоторые локальные переменные могут даже оптимизироваться, что означает, что в какой-то момент компилятор смог определить, что будущая ценность конкретной переменной больше не нужна для удовлетворения входных потребностей будущего кода (или переменная не изменяется и ее значение просто закодирован в инструкциях). Это усложняет использование отладчиков на оптимизированном коде.

Когда вы берете адрес локальной переменной, компилятор затем пытается заблокировать его до определенного адреса (возможно, сохраняя его в стеке).

Когда большинство компиляторов просматривают ваш код, они будут видеть, что имена этих локальных переменных не используются после их объявления и могут решить не хранить их значения нигде. Даже если он сохраняет эти значения в стеке, он может также нажимать другие значения в стеке перед настройкой для вызова printf. Так же, как компилятор не должен содержать переменные, которые вы назвали, он также может создавать собственные временные переменные.

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