【问题标题】:What does `int const a[5]` really mean?`int const a[5]` 的真正含义是什么?
【发布时间】:2015-07-14 17:03:55
【问题描述】:

考虑以下数组声明:

int const a[5];

从语言的语义角度来看,它是否完全等同于const int a[5]?假设是这种情况,这两个声明基本上都会读作“a 是一个由 5 个常量整数组成的数组”。

读取第一个声明的另一种方法是“a is a constant array of 5 ints”。

显然,这两个语句在逻辑上都暗示整个数组是常量;如果一个数组由 5 个常量整数组成,那么整个数组都是常量。或者,如果整个数组是常数,那么它的所有值也是常数。

我知道“常量数组”的概念有点没有意义,因为数组不是可修改的左值(也就是说,它们不能出现在赋值的左侧)。但是,在任何情况下这两个声明会产生不同的行为吗?

Cdecl.org 拒绝第一个声明为语法错误,而大多数当前编译器都接受它。)

编辑:

链接副本询问const 的顺序对于普通变量是否重要。使用数组,它有点混乱,所以我不认为这是重复的。

【问题讨论】:

  • 可能是 stackoverflow.com/questions/7633776/… 的副本?无论如何,这并不意味着什么。 5 在这里已经是一个常数。使用const int a[5]; 时,它会在C++ 中为您提供一个常量数组。请注意,这在C 中不起作用(正确)!所以对于 C 来说,它几乎被忽略了。
  • "这里的 5 已经是一个常数。" ——无关紧要。 “这并不意味着什么”——错了。 “请注意,这在 C 中不起作用(正确)!” - 错误的。 “所以对于 C 来说,它几乎被忽略了。” - 错误的。您误解了您引用的问题(与此不同)和 Kerrick SB 的回答。
  • “但是,在任何情况下这两个声明会产生不同的行为吗?” -- 关键字顺序是 syntax 的问题 -- 它与语义无关。 “Cdecl.org 拒绝第一个声明为语法错误”——然后它就坏了。
  • C 声明从里到外读取。所以这表示a 是一个由 5 个 const int 组成的数组。更改顺序表示a 是一个由 5 个 int const 组成的数组,这是没有意义的,但 C 允许您将 const 放在首位,因为语言设计者很困惑,并尽最大努力分散这种混乱。

标签: c arrays constants lvalue


【解决方案1】:

是否完全等同于const int a[5]

是的。

读取第一个声明的另一种方法是“a 是 5 个整数的常量数组”。

不是真的。您所写的声明将const 专门应用于数组元素。为了将const 应用于数组本身(而不是将其应用于数组元素),您必须执行类似

int (const a)[5];

但是这样的声明在 C 中是语法无效的。

可以通过中间 typedef 间接尝试将 const 应用于数组本身

typedef int A[5];
const A a;

但在这种情况下,根据语言规则,const 限定符“落入”数组元素,整个事情就相当于

const int a[5];

再次注意,上面的const A a; 并不立即 等同于const int a[5];。它实际上相当于前面提到的int (const a)[5]; (!)。 (将int (const a)[5]; 偷偷溜过编译器的防御是一种合法的方式。)但是int (const a)[5]; 的寿命很短——它会立即被编译器转换为const int a[5];

如果一个数组由 5 个常量整数组成,那么整个数组都是常量。或者,如果整个数组是常数,那么它的所有值也是常数。

嗯,这并不完全正确。 C 语言确实区分了数组对象本身及其元素。从概念上讲,这些是不同的实体。例如,正如您自己指出的那样,语言规范说数组是不可修改的左值。当然,这并不妨碍数组元素是可修改的。

整个数组和单个数组元素之间的概念上的区别,加上const 的“失败”行为正是导致以下不愉快情况的原因

typedef int A[5];
A a;
const A *p = &a; // ERROR!!!

即它打破了“正常”的 const 正确性规则,允许我们用 T * 值初始化 const T * 指针。 (C++ 故意更新了它的 const-correctness 规则,以使上述代码的行为“符合预期”,但 C 坚持拒绝它。)

【讨论】:

    【解决方案2】:

    我把这个放在一起:

    #include <stdio.h>
    
    int main()
    {
        int const a[5];
        const int b[5];
        int c[5];
    
        a[0] = 1;
        b[0] = 2;
        c = a;
        c = b;
    }
    

    而 gcc (4.1.2) 吐出了这个:

    gcc -o /tmp/x2 /tmp/x2.c
    /tmp/x2.c: In function ‘main’:
    /tmp/x2.c:9: error: assignment of read-only location
    /tmp/x2.c:10: error: assignment of read-only location
    /tmp/x2.c:11: error: incompatible types in assignment
    /tmp/x2.c:12: error: incompatible types in assignment
    

    所以至少基于此,似乎没有任何区别。

    【讨论】:

    • 我在提问之前做了同样的实验,但仍然不能排除两者之间的任何潜在差异。
    猜你喜欢
    • 2012-09-29
    • 2017-05-06
    • 2012-03-30
    • 2011-10-10
    • 2012-08-03
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多