我无法理解块中定义的复合文字的存储持续时间是如何自动的,推理如下:
让我们假设复合文字是在重复调用的函数或块中定义的;当第一次调用此函数时,如果计算机不在静态内存中,如何创建文字? (我的意思是他如何知道它的价值?例如它是(int [2]){2,4}或(int [5]){5,4,2,1,4})如果它以某种方式存在于任何地方,计算机如何再次知道其内容? (当他第一次去世后,当他试图再为第二次和每次后续的召唤构建它时)。
其他文字如字符串文字和普通文字的情况是它们在静态内存中,这是非常合理的,因为如果计算机没有在某处存储该值,计算机如何知道它的值。
任何人都能正确解释这个问题吗?
答案 0 :(得分: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编译器是编译器。它不仅限于从现有常量的副本创建新的数据结构。它可以生成代码,在堆栈上分配两个数组(&#34;自动存储&#34;),然后适当地填充它们。
编译器为这些复合文字分配堆栈空间并不困难,因为它确切地知道它们有多大。实际上,生成的代码与我写的代码相同:
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};
现在允许编译器使用静态文字,而不是制作不必要的副本。但是,理论上,复合文字仍然具有自动范围,并且从函数返回指向它的指针将是未定义的行为。
答案 1 :(得分:2)
您的问题没有得到正确解释。如果你想知道复合文字的范围,那么标准说:
[...]如果复合文字出现在函数体外,则该对象具有静态存储持续时间;否则,它具有与封闭块相关的自动存储持续时间。
使用复合文字进行初始化如下:
[...] 如果以递归方式输入块,则每次都会创建该对象的新实例。对象的初始值是不确定的。如果为对象指定了初始化,则每次在执行块时达到声明或复合文字时都会执行; ;否则,每次达到声明时,该值将变为不确定。
复合文字是动态创建的,是未命名的数组/结构文字。与其他变量一样,它们在内存的数据段中是stored,但除了您无法使用名称访问它之外。
答案 2 :(得分:-1)
编译不知道自动变量的值。将包含已存在的任何值。有时(例如在循环中)它们可能恰好包含上次的值,但这是运气,而不是意图。
编译器将自动变量放在堆栈上,与函数参数和返回地址混合在一起。除非代码显式初始化它们,否则自动变量将具有以前位数模式占用那些内存位置的值。