也许将对象称为“复合文字”有点误导。它实际上并不是那么字面意思。
考虑一个实际的例子是有帮助的,即使它有点愚蠢:
/* 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_;
// ...
如果您查看原始函数的生成代码,您会看到这很好。
另请注意,powers
和coefficients
都是可变的,所以我可以在函数中修改它们:
/* 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};
现在允许编译器使用静态文字,而不是制作不必要的副本。但是,理论上,复合文字仍然具有自动作用域,并且从函数返回指向它的指针将是未定义的行为。