在同一函数中定义变量及其静态等效项

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 会这样做。 当然。它警告您它指的是最内部的变量,而程序员可能不会。警告解释了行为

以上是关于在同一函数中定义变量及其静态等效项的主要内容,如果未能解决你的问题,请参考以下文章

static修饰的静态变量与实例变量的区别,及其在初始化和内存中的运行机制详解

javascript中用于自己库的静态私有变量

static静态变量和普通变量,静态函数和普通函数

static在c语言中是啥意思

如何在Python中定义静态变量

java:在java中为啥静态变量没有this引用?