V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Newyorkcity
V2EX  ›  问与答

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

  •  
  •   Newyorkcity · 2017-02-04 15:38:32 +08:00 · 1665 次点击
    这是一个创建于 2856 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #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 。。。我是真的没想通。。
    谢谢!

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

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

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

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


    最后,你的问题很好,因为是个很基础的问题。
    coderluan
        8
    coderluan  
       2017-02-04 17:44:24 +08:00   ❤️ 2
    @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
        9
    introom  
       2017-02-04 18:46:46 +08:00   ❤️ 1
    @coderluan 大哥你说的对,我看了一下 http://eel.is/c++draft/dcl.init#12 ,除了 unsigned char 以外,直接访问都是 undefined behavior, 我回复你的时候,觉得那是 unspecified behavior, 和有没有 warning 没关系。

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

    确实 C++有描述,学习了,但是 C 语言没有相关描述吧,那样对与 C 语言来说,这个还是可以叫做未定义行为吧,虽然纠结这个没啥意义。
    visionsmile
        16
    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
        17
    coderluan  
       2017-02-18 15:16:48 +08:00
    @visionsmile 懂了,谢谢
    Newyorkcity
        18
    Newyorkcity  
    OP
       2017-02-19 10:23:10 +08:00
    @visionsmile 请问这些资料在哪里可以看到?谢谢
    visionsmile
        19
    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.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   935 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:44 · PVG 04:44 · LAX 12:44 · JFK 15:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.