2016-03-23 2 views
8

Я столкнулся с проблемой при изучении C++, где локальная переменная в функции передается локальной переменной с тем же именем в другой функции, обе эти функции выполняются в основном().Локальные переменные, прошедшие (C++)

Когда запускается,

#include <iostream> 
using namespace std; 

void next(); 
void again(); 

int main() 
{ 
    int a = 2; 
    cout << a << endl; 
    next(); 
    again(); 
    return 0; 
} 

void next() 
{ 
    int a = 5; 
    cout << a << endl; 
} 

void again() 
{ 
    int a; 
    cout << a << endl; 
} 

выводит:

2 
5 
5 

Я ожидал, что снова() сказал бы нулевой или 0, так как «а» объявляется снова там, и все же, кажется, для использования значения, которое 'a' было назначено в next().

Почему next() передает значение локальной переменной 'a' снова(), если 'a' объявляется в другое время снова()?

+3

Ничего не прошло. 'a' в' again() 'не был инициализирован, любое значение возможно. – songyuanyao

+0

Согласен, что значение 'a' in - неопределенное поведение. – drescherjm

ответ

7

http://en.cppreference.com/w/cpp/language/ub

Вы правы, неинициализированная переменная не является ни-ни. Однако вам разрешено объявлять переменную и не инициализировать ее до конца. Память зарезервирована для хранения целого числа, но какое значение происходит в этой памяти, пока вы это не сделаете, может быть вообще что угодно. Некоторые компиляторы будут автоматически инициализировать переменные для нежелательных значений (чтобы помочь вам поймать ошибки), некоторые из них автоматически инициализируют значения по умолчанию, а некоторые вообще ничего не делают. Сам C++ ничего не обещает, следовательно, это неопределенное поведение. В вашем случае, с вашей простой программой, достаточно просто представить себе, как компилятор создал ассемблерный код, который повторно использовал тот же самый кусок памяти, не изменяя его. Тем не менее, это слепая везение, и даже в вашей простой программе не гарантируется. Эти типы ошибок могут быть довольно коварными, поэтому сделайте это правило: будьте бдительны в отношении неинициализированных переменных.

1

Это совершенно случайное и неопределенное поведение.

Случилось так, что у вас есть две функции, вызываемые сразу после друг друга. Оба будут иметь более или менее идентичные пролог функций и оба зарезервируют переменную точно такого же размера в стеке.

Поскольку в играх нет других переменных, и стек не изменяется между вызовами, вы просто попадаете в локальную переменную во второй функции «посадку» в том же месте, что и локальная переменная предыдущей функции.

Очевидно, это нехорошо опираться. На самом деле, это прекрасный пример того, почему вы должны всегда инициализировать переменные!

5

Неинициализированная не- static локальная переменная * встроенного типа (уф!, Который был глотка) имеет неопределенное значение. За исключением типов char, использование этого значения дает формально Неопределенное поведение, a.k.a. UB. Все может случиться, включая поведение, которое вы видите.

Видимо с компилятором и опций, в области стека, который был использован для a в вызове next, не использовался для чего-то еще до вызова again, где он был повторно использован для a в again, теперь с то же значение, что и раньше.

Но вы не можете положиться на это. С UB ничего, или ничего, может случиться.


* Или более общо типа POD, Plain Old Data. Стандартная спецификация этого несколько сложна. В C++ 11 начинается с §8.5/11: «Если для объекта не указан инициализатор, объект инициализируется по умолчанию; если инициализация не выполняется, объект с автоматической или динамической продолжительностью хранения имеет неопределенное значение. ". Где «automatic & hellip; длительность хранения "включает случай локальной переменной static. И где «никакая инициализация» может произойти двумя способами через §8.5/6, которая определяет инициализацию по умолчанию, а именно либо с помощью конструктора по умолчанию do-nothing, либо через объект, не являющийся классом или типом массива.

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