在C中,如果这不是地址常量,那是什么?

时间:2010-09-26 16:48:39

标签: c c99

如果它不是地址常量,那么,在下面的声明中,numbers究竟是什么?

int main() {
    int numbers[3] = {1,2,3};
    return 0;
}

反汇编程序显示1,2和3动态放置在本地堆栈空间中,而不是整个数组被视为常量。因此,{1,2,3}没有静态存储持续时间,因此根据C99规范,numbers 不是地址常量。

C99,第6.6.9节:“地址常量是空指针,指向静态存储持续时间对象的左值的指针,或指向函数指示符的指针......”

但是,在声明之后添加行numbers++会导致GCC 4.1.2中出现以下编译错误:

error: invalid lvalue in increment

所以它是常量,但不是地址常量。有没有人知道C99(或类似)中此类常数的正式名称?

5 个答案:

答案 0 :(得分:10)

你似乎正在发明一些不存在的东西,术语明智。

numbers是一个数组。它是int[3]类型的自动对象。它不能用于在C中形成地址常量,因为在C地址常量中需要具有静态存储持续时间的对象。

如果使用静态存储持续时间声明numbers,则应用于numbers的数组到指针转换的结果将是地址常量。在这种情况下,numbers + 1以及&numbers[2]也将是常量。

您应该注意{ 1, 2, 3 }没有静态存储持续时间。事实上,它根本没有存储时间。它不是一个对象,而只是一段名为 aggregate initializer 的语法糖。如果您希望它成为匿名对象,则必须使用复合文字语法:(int[]) { 1, 2, 3 },但无论如何它都不适用于上述语境。

numbers++不会简单编译,因为数组到指针转换的结果不是左值。您无法将++应用于非左值。事物是否恒定是无关紧要的。

你似乎得出一个奇怪的结论,如果你不能修改它,它必须是一个常数。那是完全错误的。在C术语中,常量的属性与可修改的属性几乎没有关系。术语常量指的是编译时已知的值。编译时未知的值永远不会被称为常量,即使它们不可修改。这是一个例子:自动数组的地址在编译时是未知的,所以即使该地址不可修改,它仍然不是地址常量

答案 1 :(得分:8)

numbers是函数main的非常量自动数组变量。

因为它是自动且非常量的,所以不能具有静态存储。

因为它是一个数组变量(你会注意到一个指针)它不能递增。

请注意,您可以执行

int main() {
    int numbers[3] = {1,2,3};
    int *n = numbers+1;
    n++;
    return 0;
}

答案 2 :(得分:3)

数组不是指针;请参阅comp.lang.c FAQ的第6部分。

答案 3 :(得分:0)

它不是地址常量的原因是因为它是堆栈上的地址,并且该位置取决于调用堆栈中的位置。如果直到运行时才知道它的值,那么它就不能是常数。

它也不是变量,这就是为什么你不能增加它。它只是存储位置的名称,恰好是基指针上的偏移量。 numbers[0]是有效的l值,但numbers不是。

答案 4 :(得分:-1)

numbers无法更改,因为它必须始终指向数组中的第一个元素。