C中的临时对象

Max*_*ier 6 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
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*art 1

我对此并不完全确定,但这是我从阅读 EXP35-C 中了解到的内容。不要多次修改具有临时生命周期的对象。这不是一个很好的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;
}
Run Code Online (Sandbox Code Playgroud)

在 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 要解决这个问题,许多极端情况应该是认识到数组到指针的衰减仅发生在数组左值中,但也要认识到在数组上使用下标运算符将访问元素作为直接操作,这不会不涉及数组衰减。 (2认同)