2010-06-22 2 views
0

Ниже приведен код, который я не понимаю.Запрос на запись активации в C

#include<stdio.h> 

int main(int argc, char *argv[]) 
{ 
     int num; 

     printf("\n Number: "); 
     scanf("%d", &num); 

     if (num >= 0) 
     { 
      int abs = num; 
     } 
     else 
     { 
      int abs = -num; 
     } 

     { 
      int abs; 
      printf("\n Values are %d %d", num ,abs); 
     } 
     return 0; 
} 

Когда я ввожу номер, как 4, выход Values are 4 4
Когда я ввожу номер как -4, выход Values are -4 4

Я не могу понять, как он способен печатать абсолютное значение ?. переменная abs, определенная в цикле if и else, должна быть освобождена после выхода.

Пожалуйста, дайте мне знать.

С уважением, Смуглянка

ответ

0

уморительные кода.

Он опирается на то, что все три определения абс будут выделены в одном месте в стеке из-за оптимизации компилятора.

Третий абс должен быть случайным мешком, мусор оказывается результатом предыдущей переменной с тем же именем (имя не имеет значения).

1

Эти переменные размещаются в стеке пока вы не измените его, я имею в виду, вы не получите из функции, так же, программно вы получите «новый «abs» int в последнем блоке кода, но на самом деле этот «новый» «abs» int находится там, где был старый «abs» (на STACK!), поэтому его значение по умолчанию одно и то же.

+0

Вы уверены, что это причина? Я имею в виду, откуда вы знаете, что новые «abs» и «old'abs» расположены по одному адресу в стеке? –

+0

Да, я уверен. Google для бесплатного приложения под названием Olly Debugger.Откройте приложение или что-то вроде Notepad.exe. Он остановится в исходном местоположении программы. Внизу экрана Олли вы увидите две панели - слева - память программы, сырая, а справа вы увидите сырой стек. Теперь несколько раз ударяйте F7 и видите изменения стека. Читайте о «стеке» в Википедии, чтобы понять больше. Получив идею, вы полностью поймете, что я ответил. Спросите больше, если потребуется. – Poni

+0

Кстати, я не смог воспроизвести это поведение с помощью компилятора MSVC++ 2008 (не отлаживать или выпускать сборки), который учит нас, что это поведение, зависящее от компилятора. – Poni

6

Вы абсолютно правы.

Вы видите последний блок, где int abs объявлено, что в прошлый раз? Обратите внимание: abs не инициализирован, а использование неинициализированных переменных дает неопределенные результаты. С вашим конкретным компилятором просто случается, что вам повезло, и блок памяти, в котором находится новый abs, содержит результат из предыдущей области с истекшим сроком действия.

0

Вы используете неинициализированное значение abs в printf. Стандарт языка C не требует, чтобы он был чем-то особенным, потому что он неинициализирован. Это может быть 0 или 1 или -32765

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

Вы можете посмотреть код разборки, чтобы узнать, что именно делает компилятор в терминах машинных инструкций.

+0

Демонтажный код? –

+0

Просто небольшое дополнение от отдела отдела избыточности ... Я имел в виду разборку. Или это «код разборки»? Компилятор компилирует в машинные инструкции, у большинства инструментов есть инструмент для демонтажа инструкций обратно в какой-то более удобный для пользователя язык ассемблера, чтобы вы могли видеть, что компилятор решил сделать с вашим кодом C на низком уровне. (Извиняюсь, если у меня тон глухой, и вы уже знали ...) – Digikata

1

Это называется «неопределенное поведение».

Вы получаете «стек мусора», когда вы объявляете abs с помощью printf.

Это работает так:

if (num >= 0) { 
    create 'abs' at memory address N, put 'num' in it. 
    destroy 'abs' // but leave the 'garbage' at memory address N 
} else { 
    create 'abs' at memory address N, put '-num' in it. 
    destroy 'abs' // but leave the 'garbage' at memory address N 
} 

{ 
    create 'abs' at memory address N, don't put anything in it. 
    // your compiler has decided it will reuse N. That's a valid choice. 
    // your compiler has decided it will not zero the memory at address N. That's valid. 
    read whatever was at 'abs'. // it's whatever was assigned in the conditional. 
} 

Всегда компилировать с -Wall :)

+0

+1 для опции компилятора -WaLL –

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