【问题标题】:Explanation of the life time rule in C StandardC标准中生命周期规则的解释
【发布时间】:2019-06-13 07:29:19
【问题描述】:

我正在写一个C编译器(以llvm为后端)进行练习,规则后面是the C11 standard §6.2.4

在浏览“对象的存储持续时间”部分时,有一个案例让我感到困惑:

¶8 具有结构或联合类型的非左值表达式,其中 结构或联合包含具有数组类型的成员(包括, 递归地,所有包含的结构和联合的成员)指 具有自动存储持续时间和临时生命周期的对象。它的 生命周期从计算表达式及其初始值时开始 是表达式的值。它的生命周期在评估时结束 包含完整表达式或完整声明符的结束。任何尝试 修改具有临时生命周期的对象会导致未定义 行为。

我无法想象这个案例所谈论的情况,尤其是数组成员部分(作为具有临时生命周期的非左值,具有数组成员的结构与正常的非左值有什么区别吗?) 谁能给我一个代码示例来说明这一点?

【问题讨论】:

    标签: c compiler-construction


    【解决方案1】:

    其中没有数组的临时值不必引用具有自动(或实际上任何)存储持续时间的对象。数组是特殊的,因为数组到指针的转换,关于一个可以对数组执行的唯一有用的操作,隐式地要求它有一个地址,所以编译器必须为它分配内存(因此隐式地为整个对象分配内存)包含它)。非数组左值没有地址。

    struct a { int x; };
    struct b { int y[2]; };
    void foo(int*);
    struct a one();
    struct b two();
    
    foo(&one().x); // not legal
    foo(two().y); // legal, y has an address
    

    【讨论】:

    • 所以,如果我错了,请联系我:这是否意味着: 1,如果返回值是具有数组成员的结构,则该值必须具有自动存储,即使它是临时值。 2、标准中没有提到正常临时值的存储时间应该是多少。
    • 谈论不存在于存储中的东西的存储持续时间没有多大意义。
    • 所以如果我取消引用foo(two().y) 中的参数int*,值是不确定的,这就是这条规则所说的,对吧?
    • 不,two().y 指向一个 具有 存储持续时间的对象,并且可以在其存储持续期间取消引用(尽管不能修改)它。 one().x 没有存储期限。
    • 这是因为a 可能像int 一样在寄存器中返回,因此在RAM 中没有地址?
    【解决方案2】:
    struct Foo {
      int i[1]; //structure contains a member with array type
    };
    
    struct Foo getFoo() {
      struct Foo foo;
      foo.i[0] = 1;
      return foo;
    }
    
    void test() {
      // getFoo().i life time begin;
      int *p = getFoo().i; //A non-lvalue expression with structure type
      // getFoo().i is automatic storage duration and temporary lifetime
      // getFoo().i life time end;
      assert(*p == 1); // Any attempt to modify an object with temporary lifetime results in undefined behavior.
    }
    

    【讨论】:

      【解决方案3】:

      SEI CERT C Coding Standard 中讨论了该问题(带有示例)。事实上,这是该语言的一个非常极端的例子。

      这里不复制代码——参考链接就够了。

      这个想法是,在 C99 中,当函数返回包含数组的结构时,在包含返回结构的函数的完整表达式结束之前,不得访问/改变数组。在C11中直接做是有效的。

      比如C11有效,C99无效这种:

      ++(st().arr)[0]  // try to mutate before the full expression ends.
      x=st().arr       // access array from a temporary returned structure
                       // before the sequence point at the end of full expression 
      

      【讨论】:

        猜你喜欢
        • 2021-09-12
        • 1970-01-01
        • 1970-01-01
        • 2020-06-20
        • 2021-03-09
        • 1970-01-01
        • 2021-11-25
        • 2012-01-04
        • 2012-01-17
        相关资源
        最近更新 更多