2

我不知何故无法理解块中定义的复合文字的存储持续时间是如何自动的,推理如下:

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

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

任何人都可以向我正确解释这个吗?

4

3 回答 3

3

也许将对象称为“复合文字”有点误导。它实际上并不是那么字面意思。

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

/* 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 编译器是一个编译器。它不限于从现有常量的副本创建新的数据结构。它可以生成代码,在堆栈上分配两个数组(“自动存储”),然后适当地填充它们。

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

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};

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

于 2015-02-21T20:22:05.603 回答
2

你的问题没有得到正确解释。如果您想了解复合文字的范围,那么标准会说:

C11:6.5.2.5 复合文字(P5):

[...] 如果复合文字出现在函数体之外,则该对象具有静态存储持续时间;否则,它具有与封闭块关联的自动存储持续时间。

使用复合文字进行初始化如下:

[...]如果块是递归输入的,则每次都会创建一个新的对象实例。对象的初始值是不确定的。如果为对象指定了初始化,则每次在执行块时到达声明或复合文字时都会执行它;否则,每次达到声明时,该值变得不确定。

复合文字是动态创建的,是未命名的数组/结构文字。它们像其他变量一样存储在内存的数据段中,但您不能通过名称访问它。

于 2015-02-21T20:09:03.247 回答
-1

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

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

于 2015-02-21T20:09:52.017 回答