复合文字的存储时间

storage duration of compound literals

我有点无法理解blocks中定义的复合字面量的存储时长是自动的,原因如下:

让我们假设复合文字是在一个被重复调用的函数或块中定义的;当第一次调用这个函数时,如果它不在静态内存中,计算机如何创建文字? (我的意思是他怎么知道它的价值??例如它是 (int [2]) {2,4} 还是 (int [5]) {5,4,2,1,4})如果它不知何故存在于任何地方,计算机如何再次知道其内容? (当他试图为第二次和每一次后续调用再次构建它时)在它第一次消失之后。

其他文字如字符串文字和普通文字的情况是它们在静态内存中,这是非常合理的,因为如果计算机没有将这个值存储在某个地方,他怎么知道它的值。

谁能给我解释清楚吗??

你的问题没有解释清楚。如果您想了解复合文字的范围,那么标准是这样说的:

C11:6.5.2.5 复合文字 (P5):

[...] If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

复合文字的初始化如下:

[...] If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

复合文字是即时创建的,并且是未命名的 array/struct 文字。它们 stored 像其他变量一样位于内存的数据段中,但您不能使用名称访问它。

编译器知道自动变量的值。将包含已经存在的任何值。有时(例如在循环中)它们可能恰好包含上次的值,但这是运气,而不是故意的。

编译器将自动变量放在堆栈上,与函数参数和return地址混合在一起。除非代码明确地初始化它们,否则自动变量将具有以前占用这些内存位置的任何位模式的值。

也许将对象称为 "compound literal" 有点误导。其实不是那么字面意思。

考虑一个实际的例子是有帮助的,即使它有点愚蠢:

/* This is NOT the way to solve this problem */
double cubic(double x, double a, double b, double c, double d) {
  double* powers = (double []){1, x, x*x, x*x*x};
  double* coefficients = (double []){a, b, c, d};
  double sum = 0;
  for (int i = 0; i < 4; ++i) sum += powers[i]*coefficients[i];
  return sum;
}

该函数中有两个复合文字,很明显它们都不能预先构造,因为它们依赖于函数参数。

幸运的是,C 编译器是一个编译器。它不限于从现有常量的副本创建新的数据结构。它可以生成在堆栈上分配两个数组的代码 ("automatic storage"),然后适当地填充它们。

编译器为这些复合文字分配堆栈space并不困难,因为它确切地知道它们有多大。实际上,生成的代码与我编写的代码一样:

double cubic(double x, double a, double b, double c, double d) {
  double _powers_values_[4];
  _powers_values_[0] = 1;
  _powers_values_[1] = x;
  _powers_values_[2] = x*x;
  _powers_values_[3] = x*x*x;
  double* powers = _powers_values_;
  // ...

如果您查看原始函数的生成代码,您会看到这非常好。

还要注意 powerscoefficients 都是可变的,所以我可以在函数中修改它们:

/* This is NOT the way to solve this problem */
double cubic(double x, double a, double b, double c, double d) {
  double* powers = (double []){1, x, x*x, x*x*x};
  double* coefficients = (double []){a, b, c, d};
  for (int i = 0; i < 4; ++i) coefficients[i] *= powers[i];
  for (int i = 1; i < 4; ++i) coefficients[i] += coefficients[i+1];
  return coefficients[3];
}

当然,复合文字可能只有常量值:

double* coefficients = (double []){17, 6, -3, 2.5};

但正如所写,该数组仍然是可变的,因此编译器需要为函数安排一个新的值副本。如果我愿意,我可以明确表示数组是不可变的:

const double* coefficients = (const double []){17, 6, -3, 2.5};

现在允许编译器使用静态文字,而不是进行不必要的复制。但是,理论上,复合文字仍然具有自动作用域,并且从函数返回指向它的指针将是未定义的行为。