请考虑以下示例代码:
#include <stdio.h>
int asdf = 5;
int main(void) {
sub(10);
return 0;
}
int sub (int asdf)
{
printf("%d\n",asdf);
}
在这种情况下,全局变量和本地参数都使用相同的名称asdf
。代码输出10
,因此使用局部变量。不会抛出编译错误或警告。
仍然可以从sub()
内访问全局变量,这可以通过将sub
的声明更改为
int sub (int asd)
代码输出5.所以我知道sub()
可以访问全局变量,但事实并非如此。
我无法在c标准中找到关于范围优先级的明确定义,所以我的问题是:
考虑到上面的场景,将本地和全局变量命名为仅仅是不好的做法,还是调用错误/ UB?
答案 0 :(得分:6)
来自C11草案规范
6.2.1 标识符范围
4 [...]如果是声明的声明符或类型说明符 标识符出现在块内或参数列表中 函数定义中的声明,标识符有块作用域, 它终止于相关块的末尾。
[...]如果标识符指定了两个不同的实体 名称空间,范围可能重叠。如果是这样,一个实体的范围 (内部范围)将严格地在另一方的范围之前结束 实体(外部范围)。在内部范围内,标识符 指定在内部范围内声明的实体;宣布的实体 在外部范围内隐藏(并且不可见)在内部范围内。
因此声明一个名为asdf
的函数参数会隐藏函数中的全局变量asdf
。为局部变量和全局变量赋予相同的标识符是不好的做法,但规范允许这样做。
答案 1 :(得分:2)
考虑到上面的场景,将本地和全局变量命名为仅仅是不好的做法,还是调用错误/ UB?
这是一种不好的做法,并不是未定义的行为。
考虑一个有很多作者的大型程序。在这种情况下,很难跟踪所使用的变量是函数中的变量还是全局变量。考虑如果有任何变化,如果原作者离开了工作并且新人试图理解代码,会发生什么。该程序变得更难维护。
这也是您应该避免代码中的全局变量的原因之一。
答案 2 :(得分:1)
它被称为掩蔽。当你有2个相同的变量时,全局是可见的,但是在函数中具有与全局变量同名的参数,函数参数具有更高的优先级并且掩盖全局变量。不会有任何被调用的错误,但这不是好的做法。
答案 3 :(得分:1)
Formal parameters被视为带有函数的局部变量,它们优先于全局变量。
当您使用如下方法时,您正在使用传递给方法的变量的值作为参数,这是在方法调用上确定的:
int sub (int asdf)
{
printf("%d\n",asdf);
}
例如:
sub(10); // asdf is being assigned the value of 10 and asdf is a different variable.
实际上和以下相同:
int sub (int adf)
{
printf("%d\n",adf);
}
这无法使用传递给方法的int参数,因此正在使用全局变量值。
int sub (int adf)
{
printf("%d\n",asdf);
}
或者您可以调用原始方法,如:
sub(asdf);
无论哪种方式,它都没有真正的价值,它将命名为全局变量。因为它可以使用int anything
实现,然后可以访问全局变量。它确实可能造成混淆。
任何模糊的命名都被认为是不好的做法。
然后出现了使用全局变量的问题,这是一个微不足道的问题以及这可能会导致程序跟踪的问题,这在其他答案中已经提到过了。
答案 4 :(得分:1)
是的,显然,命名两个具有相同名称的变量是一种不好的做法。
您可以在这些方案中使用关键字extern
进行区分。请考虑以下示例。
#include <stdio.h>
int a = 12;
int main(void)
{
int a = 15;
printf("Inside a's main local a = : %d\n", a);
{
extern int a;
printf("In a global a = %d\n", a);
}
return 0;
}
它会给op
Inside a's main local a = : 15
In a global a = 12
编译器不会抛出任何错误。
答案 5 :(得分:0)
你可以称之为不好的做法,因为它会使你的代码难以阅读,但这不会导致错误。本地名称始终覆盖全局名称。
想象一下,如果本地名称没有覆盖全局名称会发生什么:当您与外部代码连接时,您通常不知道已经选择的变量名称。在这种情况下,外部代码可能会突然改变变量的值而不会注意到它,只是因为您将全局变量命名为与其局部变量相同。
答案 6 :(得分:0)
全局变量当然是不好的做法。除此之外,我在这里看不到任何关于变量名称优先级的意外情况。
很明显编译器总是首先在最窄的范围内查找变量名称,比如说x
。
x
,它将停在那里,并且永远不会检查任何其他范围。当您有两个变量asdf
,一个本地变量和一个全局变量时就是这种情况。因为编译器在asdf
中找到了sub()
,所以它永远不会寻找全局的x
。此行为也称为名称隐藏。int i = 10;
for( int i = 5; i < 9; i++ )
{
printf( "i = %d (inside for loop)\n", i ); // <-- i = 10 is hidden in this loop
}
printf( "i = %d (outside for loop)\n", i );
时,它才会将搜索扩展到更广泛的范围,扩展到全局范围。此名称隐藏事项也适用于不同的范围,例如:
void
顺便说一下,你的原型是不正确的,返回类型应该是int
,而不是 。void sub (int asdf);
const char* global = "Example";
void foo() {
printf("%s\n", global );
}