C中的临时对象

时间:2019-04-28 06:16:02

标签: c language-lawyer

在C11中,术语temporary lifetime被定义:

  

C11 6.2.4p8:   具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(递归地,包括所有包含的结构和联合的成员)是指具有自动存储期限和临时生存期的对象。 36)当表达式被求值并且其初始值为表达式的值时,其生命周期开始。当包含完整表达式或完整声明符的求值结束时,其生存期结束。任何试图使用临时生存期修改对象的尝试都会导致未定义的行为。

我想知道为什么这仅适用于具有数组类型成员的结构或联合类型的右值。数组有什么特别之处?

struct x { int xx; };
struct y { int yy[1]; };

(struct x)   { 42 };    // *not* a temporary object
(struct y) { { 42 } };  // a temporary object

为什么第一个对象不是临时对象,而第二个对象是临时对象?

2 个答案:

答案 0 :(得分:1)

此限制仅适用于包含数组的临时对象的原因是,该限制仅与包含数组的临时对象相关-当您拥有一个不包含数组的未命名非左值对象时,您将无法从对象获取地址;明确禁止使用&。但是,当对象包含一个数组,并且按名称访问该数组时,您将隐式获取该数组第一个元素的地址。在C11之前,尝试对该指针执行任何操作都是未定义的行为。使用C11,您现在可以使用对象(和指针),而无法对其进行修改。

答案 1 :(得分:0)

我对此不太确定,但这是我从阅读中了解的内容  EXP35-C. Do not modify objects with temporary lifetime几次。这不是一个很好的language-lawyer答案,但我将尝试用更简单的术语进行解释。

通常,C函数无法返回数组。但是,您(尝试)通过在结构中粘贴数组并返回该数组来解决此问题。考虑以下示例代码:

#include <stdio.h>

struct X { char a[8]; };

struct X salutation(void) {
  struct X result = { "Hello" };
  return result;
}

struct X addressee(void) {
  struct X result = { "world" };
  return result;
}

int main(void) {
  printf("%s, %s!\n", salutation().a, addressee().a);
  return 0;
}

在C99中,此程序调用了未定义的行为。您甚至不允许访问结构内部的数组。原因是当带有局部变量的函数返回时,数组的生存期结束。

在C11中,他们稍微放宽了规则,以便您可以访问该数组,但不允许您对其进行修改。

由于存在这种细微的差异,因此EXP35-C规则建议不要执行任何操作。而是将包含数组的结构结果保存到局部变量:

#include <stdio.h>

struct X { char a[8]; };

struct X salutation(void) {
  struct X result = { "Hello" };
  return result;
}

struct X addressee(void) {
  struct X result = { "world" };
  return result;
}

int main(void) {
  struct X my_salutation = salutation();
  struct X my_addressee = addressee();

  printf("%s, %s!\n", my_salutation.a, my_addressee.a);
  return 0;
}