在同一函数中定义变量及其静态等效项
Posted
技术标签:
【中文标题】在同一函数中定义变量及其静态等效项【英文标题】:Defining a variable and its static equivalent in the same function 【发布时间】:2018-07-10 09:57:49 【问题描述】:我不明白下面的代码是如何工作的:
#include "stdio.h"
int main(void)
int i = 3;
while(i--)
static int i = 100;
i--,
printf("%d\n", i);
return 0;
使用 Clang 或 GCC 编译的代码会打印以下输出:
99
98
97
有人可以向我解释这里发生了什么吗?看起来两个操作是在一条指令中完成的,而且不止一次。它是未定义的行为吗? 我在 C++ 中观察到相同的行为。
【问题讨论】:
可能重复***.com/questions/22120362/… 如果你打开你的编译器标志,你会看到编译器警告你声明会影响另一个。至少 GCC 会这样做。 "看起来两个操作是在一条指令中完成的,而且不止一次。"您能否具体说明您的意思以及您期望的输出? 也许题外话了,但他们为什么要设计编译器来允许阴影?我能想到的唯一用例可能是您包含一个使用通用名称的 c 库? “两个操作在一条指令中完成”——你在哪里看到这样的东西? 【参考方案1】:这不是未定义的行为。
#include "stdio.h"
int main(void)
int i = 3; //first i
while(i--)
static int i = 100; //second i
i--,
printf("%d\n", i);
return 0;
在 while 循环体中,大多数本地 i
(第二个 i
)是首选。在 while 循环中检查条件时,它不知道正文中有什么。所以先选i
是没有问题的。
【讨论】:
只是一个信息.. static int i = 100;只执行一次.. 如果不是静态结果将是 99, 99 , 99 @SreeraghAR True. @Sreeragh A R:这是误导。在 C 和 C++ 中,i
被静态地 初始化(又名“在编译时”)。它甚至从未真正执行过一次。而C语言甚至没有“执行”静态对象初始化的概念。尽管初始化器看起来写在函数内部,但实际的初始化发生在它的边界之外。
@AnT 你可能是对的..我只是想表达如果它不是静态的结果会有所不同..【参考方案2】:
***对此有非常突出的评价:
在计算机编程中,当在某个范围(决策块、方法或内部类)中声明的变量与在外部范围中声明的变量具有相同的名称时,就会发生变量遮蔽。在标识符(名称,而不是变量)级别,这称为名称屏蔽。这个外部变量被称为被内部变量遮蔽,而内部标识符被称为掩盖了外部标识符。
现在,它在块内找到静态变量并对其进行处理,但 while 条件减少了在块外声明的 i
。范围不同 - 使用 i
的正确值是没有问题的。这是合法的 C 代码,但不一定是写东西的好方法。
事实上这样做gcc -Wshadow progname.c
给了
progname.c: In function 'main':
progname.c:7:20: warning: declaration of 'i' shadows a previous local [-Wshadow]
static int i=2;
^
progname.c:5:9: warning: shadowed declaration is here [-Wshadow]
int i=2;
^
来自标准§6.2.1p4
...如果一个标识符在同一个名称空间中指定了两个不同的实体,则范围可能会重叠。如果是这样,一个实体的范围(内部范围)将严格在另一个实体的范围(外部范围)之前结束。 在内部范围内,标识符指定在内部范围内声明的实体;在外部范围内声明的实体在内部范围内隐藏(不可见)。
【讨论】:
【参考方案3】:可以在嵌套范围内声明相同的命名变量。编译器将它们视为不同的变量。这非常令人困惑,但您每次访问的变量都是在最内部范围内声明的变量。 while
外面是int i = 3;
,里面是static int i = 100;
#include "stdio.h"
int main(void)
int i = 3; // outer i
while(i--) // outer i
static int i = 100; // inner i
i--, // inner i
printf("%d\n", i); // inner i
return 0;
如果这是一个非 main 函数,那么第二次调用它会产生
96
95
94
等等……
【讨论】:
如果你打开你的编译器标志,你会看到编译器警告你声明会影响另一个。至少 GCC 会这样做。 当然。它警告您它指的是最内部的变量,而程序员可能不会。警告解释了行为以上是关于在同一函数中定义变量及其静态等效项的主要内容,如果未能解决你的问题,请参考以下文章