C 语言,问一个挺基础的关于作用域的问题

2017-02-04 15:38:32 +08:00
 Newyorkcity
#include <stdio.h>

int main(){
	int i = 5;
	{
		int i = i;
		printf("i=%d\n",i);
	}
	printf("i=%d\n",i);
}

我的想法是这样的,赋值运算符不是从右向左结合么,所以 i = i 时,右侧的 i 还是父块中 i ,左边的 i 被赋值,应该也等于 5 ,但此时已经是子块中的本地变量了。
不过觉得奇怪的是,输出结果是这样的:
i = 1
i = 5
我完全不理解这个 i=1 是怎么来的?我反复尝试了几次之后都是 i=1 ,我个人觉得就算我想的不对,那也应该报错或者是被赋一个乱七八糟的随机数,但是这个 1 。。。我是真的没想通。。
谢谢!

1586 次点击
所在节点    问与答
19 条回复
corvofeng
2017-02-04 15:50:47 +08:00
试验了下 gcc6.3 输出是 0 , 5
clang3.9 输出是 4195312 , 5 ,
可能这种赋值没法预测结果吧
kokutou
2017-02-04 15:53:47 +08:00
int j = i;
这样比较符合你的预期。。。
yuchting
2017-02-04 15:56:36 +08:00
这个真的和编译器有关,按照我学习的理论应该是 5 , 5 。这个属于调戏编译器的代码,现实开发中需要极度避免。
Newyorkcity
2017-02-04 15:58:46 +08:00
coderluan
2017-02-04 16:02:22 +08:00
nodeath
2017-02-04 16:39:10 +08:00
应该理解为先定义在赋值啊,你赋值的那个 i 已经是局域变量了。
introom
2017-02-04 16:47:16 +08:00
@coderluan 这不是未定义行为。。。。

楼主,你写完 int i 的时候, i 就在作用域可见,所以右边 i 指代左边没有初始化的 i.

这种基础语法认知应当所有主流编译器都会报 warning 的。

具体名称,在 spec 的前面就有,我在手机,打字已然很累,所以就不给具体链接了。


最后,你的问题很好,因为是个很基础的问题。
coderluan
2017-02-04 17:44:24 +08:00
@introom

warning 是编译器定义的, undefined behavior 是标准定义的,不能说有 warning 就不能叫 undefined behavior 了吧。
按标准来说,使用了 uninitialized 变量叫做 undefined behavior 了。
http://stackoverflow.com/questions/11962457/why-is-using-an-uninitialized-variable-undefined-behavior-in-c
introom
2017-02-04 18:46:46 +08:00
@coderluan 大哥你说的对,我看了一下 http://eel.is/c++draft/dcl.init#12 ,除了 unsigned char 以外,直接访问都是 undefined behavior, 我回复你的时候,觉得那是 unspecified behavior, 和有没有 warning 没关系。

安腾处理器蛮有意思的, NaT bit,直接访问 trap 。。。。学习了。
Newyorkcity
2017-02-04 20:47:35 +08:00
@introom
@coderluan
给大佬们递茶
htfy96
2017-02-04 21:15:21 +08:00
话说最近 C++委员会的 Scott Meyer 好像发推说要在下个 C++版本中让 int x = x 这种语法直接 ill-formed
htfy96
2017-02-04 21:17:28 +08:00
@htfy96 zz 了,全都记错了,是 Herb Sutter
coderluan
2017-02-04 21:22:18 +08:00
@introom 我就是看见编译器结果不同就叫未定义行为,也是你说了之后我才去查的... 哈哈
visionsmile
2017-02-18 13:48:15 +08:00
@corvofeng
@Newyorkcity
@coderluan
@introom
@htfy96 题主这个是 Point of declaration 的问题,在 C++标准中是有描述的:

The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below. [ Example:
unsigned char x = 12;
{ unsigned char x = x; }
Here the second x is initialized with its own (indeterminate) value. — end example ]
coderluan
2017-02-18 14:11:06 +08:00
@visionsmile

确实 C++有描述,学习了,但是 C 语言没有相关描述吧,那样对与 C 语言来说,这个还是可以叫做未定义行为吧,虽然纠结这个没啥意义。
visionsmile
2017-02-18 14:59:19 +08:00
@coderluan 这个不叫未定义行为啊,应该叫这个 object 具有不确定的值(indeterminate value)
C 语言标准里面没有直接提到这种写法,但是也可以间接地推导出来:
>If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
以及:
>If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.

未定义行为是标准没有描述它会产生什么样的行为(行为不可预测),但是就这个问题而言,标准也是规定了它具有不确定的值(也就是描述了它会产生不确定值的行为)..所以就不是未定义行为....
coderluan
2017-02-18 15:16:48 +08:00
@visionsmile 懂了,谢谢
Newyorkcity
2017-02-19 10:23:10 +08:00
@visionsmile 请问这些资料在哪里可以看到?谢谢
visionsmile
2017-02-19 10:45:29 +08:00
@Newyorkcity 我整理了一个 C/C++相关的文档列表,可以在这里下载: [doc.imzlp.me]( http://doc.imzlp.me/) ,我上面提到的 C++标准是 ISO/IEC 14882:2014 和 C 标准 ISO/IEC 9899:2011.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/338047

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX