@Vadiklk, так что задавайте вопрос, начинающийся с "Почему"
Андрей
1
ideone.com/t9Bbe Чего вы ожидаете? Результат не соответствует вашим ожиданиям? Почему вы ждали своего результата?
eckes
Ответы:
187
Здесь есть две проблемы: срок службы и область действия.
В области видимости переменной можно увидеть имя переменной. Здесь x виден только внутри функции foo ().
Время жизни переменной - это период, в течение которого она существует. Если бы x был определен без ключевого слова static, время жизни было бы от входа в foo () до возврата из foo (); поэтому он будет повторно инициализирован до 5 при каждом вызове.
Ключевое слово static продлевает время жизни переменной до времени жизни программы; например, инициализация происходит один раз и только один раз, а затем переменная сохраняет свое значение - каким бы оно ни было - во всех будущих вызовах foo ().
в каких сценариях нам нужно объявить переменную статической внутри функции? Просто интересно знать, поскольку я не использовал это раньше?
Akay
Я бы сказал спасибо, но на все это был дан ответ в самом верху страницы. меня смешит то, что люди не просто запускают свой собственный код. xD
Puddle
Это неверный ответ. В тот момент, когда вы думаете о рекурсивных функциях, определения, описанные здесь, не объясняют их поведения!
Филип Коулинг, 03
53
Выход : 6 7
Причина : статическая переменная инициализируется только один раз (в отличие от автоматической переменной), и дальнейшее определение статической переменной будет пропущено во время выполнения. И если он не инициализирован вручную, он автоматически инициализируется значением 0. Так,
void foo(){staticint x =5;// assigns value of 5 only once
x++;
printf("%d", x);}int main(){
foo();// x = 6
foo();// x = 7return0;}
staticint x =5;void foo(){
x++;
printf("%d", x);}int main(){
foo();
foo();return0;}
Все, что ключевое слово static делает в этой программе, - это сообщает компилятору (по сути): «Эй, у меня есть переменная, к которой я не хочу, чтобы кто-либо другой получал доступ, не говорите никому, что она существует».
Внутри метода ключевое слово static сообщает компилятору то же самое, что и выше, но также «никому не говорите, что это существует вне этой функции, оно должно быть доступно только внутри этой функции».
Ну, на самом деле это не то же самое. В X все еще есть проблема с областью видимости. В этом примере вы можете тыкать и вертеться xв main; это глобально. В исходном примере xбыл локальным для foo, видимым только внутри этого блока, что обычно предпочтительнее: если foo существует для поддержки xпредсказуемым и видимым образом, то позволять другим тыкать его, как правило, опасно. Еще одно преимущество - держать его в объеме. foo() Он также сохраняет foo()портативность.
user2149140
2
@ user2149140 «никому не говори, что это существует вне этой функции, это должно быть доступно только внутри этой функции»
DCShannon 01
3
Хотя вы рассмотрели проблему области видимости из-за того, где объявлена переменная, описание static как влияющего на область видимости, а не на время жизни, кажется неверным.
DCShannon 01
1
@Chameleon Вопрос помечен как c, поэтому в этом контексте ваш пример будет незаконным в глобальной области. (C требует постоянных инициализаторов для глобальных объектов, C ++ - нет).
Ричард Дж. Росс III
5
Статическая переменная внутри функции имеет срок жизни, пока выполняется ваша программа. Он не будет выделяться каждый раз, когда ваша функция вызывается, и освобождается, когда ваша функция возвращается.
Сказать, что это как «глобальная» переменная, а затем сказать, КРОМЕ, что вы не можете получить к ней доступ, - это оксюморон. Глобальный означает доступный где угодно. Что в этом случае статической INSIDE функции НЕ доступно везде. Проблема в OP, как отмечали другие, связана с объемом и сроком службы. Пожалуйста, не путайте людей с использованием термина «глобальный» и вводите их в заблуждение относительно области видимости переменной.
ChuckB
@ChuckB: Верно. Починил это. Ну прошло 6 лет. Мой предыдущий ответ был восприятием 6 лет назад!
Донотало
5
Выход: 6,7
причина
Объявление xнаходится внутри, fooно x=5инициализация происходит вне foo!
Здесь нам нужно понять, что
staticint x =5;
это не то же самое, что
staticint x;
x =5;
В других ответах здесь использовались важные слова, область видимости и время жизни, и было указано, что область действия xнаходится от точки ее объявления в функции fooдо конца функции foo. Например, я проверил, переместив объявление в конец функции, и это xстало необъявленным в x++;заявлении.
Таким образом, часть static int x(область действия) оператора действительно применяется там, где вы ее читаете, где-то ВНУТРИ функции и только оттуда и далее, а не над ней внутри функции.
Однако часть x = 5(время жизни) оператора - это инициализация переменной и выполнение ВНЕШНЕЙ функции во время загрузки программы. Переменная xрождается со значением5 когда программа загружается.
Я прочитал это в одном из комментариев: « Кроме того, это не решает действительно сбивающую с толку часть, а именно то, что инициализатор пропускается при последующих вызовах. Он пропускается при всех вызовах. Инициализация переменной происходит вне кода функции.
Значение 5 теоретически устанавливается независимо от того, вызывается ли вообще foo, хотя компилятор может оптимизировать функцию, если вы ее нигде не вызываете. Значение 5 должно быть в переменной до вызова foo.
Внутри fooзаявленияstatic int x = 5; вряд ли вообще будет генерироваться какой-либо код.
Я обнаружил, что адрес xиспользуется, когда я помещаю функцию fooв свою программу, а затем (правильно) предположил, что это же местоположение будет использовано, если я снова запущу программу. На частичном снимке экрана ниже показано, что xзначение имеет значение 5еще до первого вызова foo.
На выходе будет 6 7. Статическая переменная (внутри функции или нет) инициализируется ровно один раз перед выполнением какой-либо функции в этой единице перевода. После этого он сохраняет свое значение до тех пор, пока не будет изменен.
Вы уверены, что статика инициализируется перед вызовом функции, а не при первом вызове функции?
Джесси Пеппер
@JessePepper: По крайней мере, если память не изменяет, это зависит от того, говорите ли вы о C ++ 98/03 или C ++ 11. В C ++ 98/03 я считаю, что это так, как описано выше. В C ++ 11 многопоточность делает это практически невозможным, поэтому инициализация выполняется при первом входе в функцию.
Джерри Коффин,
2
На самом деле я думаю, что ты ошибаешься. Я думаю, что даже до C ++ 11 он инициализировался только при вызове функции. Это важно для общего решения проблемы зависимости статической инициализации.
Джесси Пеппер,
2
Vadiklk,
Зачем ...? Причина в том, что статическая переменная инициализируется только один раз и сохраняет свое значение на протяжении всей программы. означает, что вы можете использовать статическую переменную между вызовами функций. также его можно использовать для подсчета «сколько раз вызывается функция»
main(){staticint var =5;
printf("%d ",var--);if(var)
main();}
и ответ будет 5 4 3 2 1, а не 5 5 5 5 5 5 .... (бесконечный цикл), как вы ожидаете. опять же, причина в том, что статическая переменная инициализируется один раз, при следующем вызове main () она не будет инициализирована значением 5, потому что она уже инициализирована в программе. Таким образом, мы можем изменить значение, но не можем повторно инициализировать. Вот как работает статическая переменная.
или вы можете рассмотреть в соответствии с хранилищем: статические переменные хранятся в разделе данных программы, а переменные, которые хранятся в разделе данных, инициализируются один раз. и до инициализации они хранятся в разделе BSS.
В свою очередь, автоматические (локальные) переменные сохраняются в стеке, и все переменные в стеке повторно инициализируются все время, когда функция вызывается, поскольку для этого создается новый FAR (запись активации функции).
хорошо, для большего понимания, сделайте приведенный выше пример без «статики» и сообщите, каким будет результат. Это заставит вас понять разницу между этими двумя.
Статические локальные переменные: переменные, объявленные как статические внутри функции, статически выделяются, имея ту же область действия, что и автоматические локальные переменные. Следовательно, любые значения, которые функция помещает в свои статические локальные переменные во время одного вызова, все равно будут присутствовать при повторном вызове функции.
Это ужасно! «переменные, объявленные как статические внутри функции, выделяются статически» - это ничего не объясняет, если вы еще не знаете, что это значит!
@Blank: ну, я думал, что второе предложение было для этого. Хотя я полагаю, что вы правы, его следует сформулировать получше.
Эндрю Уайт
Кроме того, это не решает действительно сбивающую с толку часть, заключающуюся в том, что инициализатор пропускается при последующих вызовах.
Tom Auger
статическое выделение означает отсутствие стека или кучи.
Хамелеон
1
Вы получите 6 7, напечатанное как, что легко проверить, и вот почему: когда foo первом вызове статическая переменная x инициализируется значением 5. Затем она увеличивается до 6 и печатается.
Теперь о следующем звонке foo. Программа пропускает инициализацию статической переменной и вместо этого использует значение 6, которое было присвоено x в последний раз. Выполнение продолжается как обычно, и вы получаете значение 7.
x - глобальная переменная, которая видна только из foo (). 5 - его начальное значение, хранящееся в разделе кода .data. Любая последующая модификация перезаписывает предыдущее значение. В теле функции нет кода присваивания.
6 и 7 Поскольку статическая переменная инициализируется только один раз, Итак, 5 ++ становится 6 при 1-м вызове, 6 ++ становится 7 при 2-м вызове. Примечание. Когда происходит 2-й вызов, он принимает значение x, равное 6, а не 5, потому что x является статической переменной.
По крайней мере, в C ++ 11, когда выражение, используемое для инициализации локальной статической переменной, не является constexpr (не может быть оценено компилятором), инициализация должна происходить во время первого вызова функции. Самый простой пример - напрямую использовать параметр для инициализации локальной статической переменной. Таким образом, компилятор должен выдать код, чтобы угадать, является ли вызов первым или нет, что, в свою очередь, требует локальной логической переменной. Я собрал такой пример и убедился, что это правда, посмотрев код сборки. Пример может быть таким:
void f(int p ){staticconstint first_p = p ;
cout <<"first p == "<< p << endl ;}void main(){
f(1); f(2); f(3);}
конечно, когда выражением является constexpr, это не требуется, и переменная может быть инициализирована при загрузке программы с использованием значения, сохраненного компилятором в выходном ассемблерном коде.
Ответы:
Здесь есть две проблемы: срок службы и область действия.
В области видимости переменной можно увидеть имя переменной. Здесь x виден только внутри функции foo ().
Время жизни переменной - это период, в течение которого она существует. Если бы x был определен без ключевого слова static, время жизни было бы от входа в foo () до возврата из foo (); поэтому он будет повторно инициализирован до 5 при каждом вызове.
Ключевое слово static продлевает время жизни переменной до времени жизни программы; например, инициализация происходит один раз и только один раз, а затем переменная сохраняет свое значение - каким бы оно ни было - во всех будущих вызовах foo ().
источник
Выход : 6 7
Причина : статическая переменная инициализируется только один раз (в отличие от автоматической переменной), и дальнейшее определение статической переменной будет пропущено во время выполнения. И если он не инициализирован вручную, он автоматически инициализируется значением 0. Так,
источник
6 7
компилятор обеспечивает то, что инициализация статической переменной не происходит каждый раз при входе в функцию
источник
Это то же самое, что и следующая программа:
Все, что ключевое слово static делает в этой программе, - это сообщает компилятору (по сути): «Эй, у меня есть переменная, к которой я не хочу, чтобы кто-либо другой получал доступ, не говорите никому, что она существует».
Внутри метода ключевое слово static сообщает компилятору то же самое, что и выше, но также «никому не говорите, что это существует вне этой функции, оно должно быть доступно только внутри этой функции».
надеюсь, это поможет
источник
x
в main; это глобально. В исходном примереx
был локальным для foo, видимым только внутри этого блока, что обычно предпочтительнее: если foo существует для поддержкиx
предсказуемым и видимым образом, то позволять другим тыкать его, как правило, опасно. Еще одно преимущество - держать его в объеме.foo()
Он также сохраняетfoo()
портативность.c
, поэтому в этом контексте ваш пример будет незаконным в глобальной области. (C требует постоянных инициализаторов для глобальных объектов, C ++ - нет).Статическая переменная внутри функции имеет срок жизни, пока выполняется ваша программа. Он не будет выделяться каждый раз, когда ваша функция вызывается, и освобождается, когда ваша функция возвращается.
источник
Выход: 6,7
причина
Объявление
x
находится внутри,foo
ноx=5
инициализация происходит внеfoo
!Здесь нам нужно понять, что
это не то же самое, что
В других ответах здесь использовались важные слова, область видимости и время жизни, и было указано, что область действия
x
находится от точки ее объявления в функцииfoo
до конца функцииfoo
. Например, я проверил, переместив объявление в конец функции, и этоx
стало необъявленным вx++;
заявлении.Таким образом, часть
static int x
(область действия) оператора действительно применяется там, где вы ее читаете, где-то ВНУТРИ функции и только оттуда и далее, а не над ней внутри функции.Однако часть
x = 5
(время жизни) оператора - это инициализация переменной и выполнение ВНЕШНЕЙ функции во время загрузки программы. Переменнаяx
рождается со значением5
когда программа загружается.Я прочитал это в одном из комментариев: « Кроме того, это не решает действительно сбивающую с толку часть, а именно то, что инициализатор пропускается при последующих вызовах. Он пропускается при всех вызовах. Инициализация переменной происходит вне кода функции.
Значение 5 теоретически устанавливается независимо от того, вызывается ли вообще foo, хотя компилятор может оптимизировать функцию, если вы ее нигде не вызываете. Значение 5 должно быть в переменной до вызова foo.
Внутри
foo
заявленияstatic int x = 5;
вряд ли вообще будет генерироваться какой-либо код.Я обнаружил, что адрес
x
используется, когда я помещаю функциюfoo
в свою программу, а затем (правильно) предположил, что это же местоположение будет использовано, если я снова запущу программу. На частичном снимке экрана ниже показано, чтоx
значение имеет значение5
еще до первого вызоваfoo
.источник
На выходе будет
6 7
. Статическая переменная (внутри функции или нет) инициализируется ровно один раз перед выполнением какой-либо функции в этой единице перевода. После этого он сохраняет свое значение до тех пор, пока не будет изменен.источник
Vadiklk,
Зачем ...? Причина в том, что статическая переменная инициализируется только один раз и сохраняет свое значение на протяжении всей программы. означает, что вы можете использовать статическую переменную между вызовами функций. также его можно использовать для подсчета «сколько раз вызывается функция»
и ответ будет 5 4 3 2 1, а не 5 5 5 5 5 5 .... (бесконечный цикл), как вы ожидаете. опять же, причина в том, что статическая переменная инициализируется один раз, при следующем вызове main () она не будет инициализирована значением 5, потому что она уже инициализирована в программе. Таким образом, мы можем изменить значение, но не можем повторно инициализировать. Вот как работает статическая переменная.
или вы можете рассмотреть в соответствии с хранилищем: статические переменные хранятся в разделе данных программы, а переменные, которые хранятся в разделе данных, инициализируются один раз. и до инициализации они хранятся в разделе BSS.
В свою очередь, автоматические (локальные) переменные сохраняются в стеке, и все переменные в стеке повторно инициализируются все время, когда функция вызывается, поскольку для этого создается новый FAR (запись активации функции).
хорошо, для большего понимания, сделайте приведенный выше пример без «статики» и сообщите, каким будет результат. Это заставит вас понять разницу между этими двумя.
Спасибо Джавед
источник
Давайте просто прочитаем статью в Википедии о статических переменных ...
источник
Вы получите 6 7, напечатанное как, что легко проверить, и вот почему: когда
foo
первом вызове статическая переменная x инициализируется значением 5. Затем она увеличивается до 6 и печатается.Теперь о следующем звонке
foo
. Программа пропускает инициализацию статической переменной и вместо этого использует значение 6, которое было присвоено x в последний раз. Выполнение продолжается как обычно, и вы получаете значение 7.источник
x - глобальная переменная, которая видна только из foo (). 5 - его начальное значение, хранящееся в разделе кода .data. Любая последующая модификация перезаписывает предыдущее значение. В теле функции нет кода присваивания.
источник
6 и 7 Поскольку статическая переменная инициализируется только один раз, Итак, 5 ++ становится 6 при 1-м вызове, 6 ++ становится 7 при 2-м вызове. Примечание. Когда происходит 2-й вызов, он принимает значение x, равное 6, а не 5, потому что x является статической переменной.
источник
По крайней мере, в C ++ 11, когда выражение, используемое для инициализации локальной статической переменной, не является constexpr (не может быть оценено компилятором), инициализация должна происходить во время первого вызова функции. Самый простой пример - напрямую использовать параметр для инициализации локальной статической переменной. Таким образом, компилятор должен выдать код, чтобы угадать, является ли вызов первым или нет, что, в свою очередь, требует локальной логической переменной. Я собрал такой пример и убедился, что это правда, посмотрев код сборки. Пример может быть таким:
конечно, когда выражением является constexpr, это не требуется, и переменная может быть инициализирована при загрузке программы с использованием значения, сохраненного компилятором в выходном ассемблерном коде.
источник