在C语言中使用const关键字

6

我一直在看源代码,然后我遇到了这段代码

    static char const *const delimit_method_string[] =
    {
        "none", "prepend", "separate", NULL
    };

我曾以为我知道在C语言中const关键字的含义,但在看到这个语法之后,我感到困惑,因为我无法解码这个语法的含义,所以我想了解这样使用const的含义。我在互联网上搜索,发现在stackOverflow上有一些类似以下问题:
  1. C/C++签名中两个const的含义
  2. 双重const声明
但是我仍然不理解代码片段中语法的含义,可能是因为我对C的基础知识掌握不够好,但我真的很想提高它。
因此,我编写了一些代码来了解那个语法如何工作,这就是我尝试的内容:
    #include <stdio.h>
    
    int main()
    {
        char a = 'A';
        char b = 'B';
        char const * const ptr = &a;

        ptr = &b;

        printf("a is %c\n", *ptr);
        printf("a is %c", a);
    
        return 0;
    }

我得到了这个输出,有些是我所预期的。
$ gcc test.c
test.c: In function 'main':
test.c:9:13: error: assignment of read-only variable 'ptr'
    9 |         ptr = &b;
      |  

                    ^

我修改了代码并再次进行了测试,

    #include <stdio.h>
    
    int main()
    {
        char a = 'A';
        char b = 'B';
        char const const *ptr = &a;
    
        ptr = &b;

        printf("a is %c\n", *ptr);
        printf("a is %c", a);
    
        return 0;
    }

这次输出结果并非我所期望的内容,

$ ./a.exe
a is B
a is A

请问有人能解释在C语言中使用const的正确方式是什么,以及第一个代码片段中的语法如何工作?


你对第二个片段有什么期望? - tstanisl
@tstanisl 我以为我会像之前一样出现错误,但是这次没有出现任何错误。 - ABHIJITH EA
2
我认为我的见解不足以回答这个问题,但我总是尝试反向阅读声明:所以static char const *const delimit_method_stringdelimit_method_string是一个指向const(不可修改的)charconst指针*,它是static的。这有助于我理解它。 - Dávid Tóth
2
@DavidTóth 是的,那很有道理,谢谢你的技巧 :) - ABHIJITH EA
2个回答

4
这份声明。
static char const *const delimit_method_string[] =
{
  "none", "prepend", "separate", NULL
};

声明了一个名为delimit_method_string的指向字符串字面量的指针数组。

在C语言中,与C++相反,字符串字面量具有非常量字符数组的类型。尽管如此,您不能更改字符串字面量。任何试图更改字符串字面量的尝试都会导致未定义的行为。因此,最好以以下方式声明指向字符串字面量的指针,例如:

const char *s = "Hello";

那么你可以这样声明上述数组:

static char const * delimit_method_string[] =
{
  "none", "prepend", "separate", NULL
};

但是声明这个数组的程序员还想将其声明为一个常量数组,也就是说他希望它的元素不能被改变。
例如,对于上面的声明,你可以写成:
delimit_method_string[0] = "all";

为了防止这样的情况发生,数组的元素必须是常量。要做到这一点,您需要编写:
static char const * const delimit_method_string[] =
{
  "none", "prepend", "separate", NULL
};

由于第二个限定符 const,数组元素指针类型为 const char * 的元素是常量。

为了让它更加清晰,考虑以下声明。

char *p;

该声明声明了一个指向非常量对象的非常量指针,其类型为char
const char *p;

这个声明声明了一个指向常量对象类型为char的非常量指针。
const char * const p;

该声明声明了一个指向类型为char的常量对象的常量指针。

最后一个声明可以重写为

const char ( * const p );

关于你的声明

char const const *ptr = &a;

因为两个限定符都指向类型说明符char,所以其中一个const是多余的。


1
好的解释!您可以补充说明,staticconstchar可以以任何顺序出现在*之前,具有相同的含义。 static const char *pstatic char const *p是等效的,以及char const static *p,这非常令人困惑 :) - chqrlie

3
char const const *ptr = &a;

这个双重的 const 没有任何特殊含义,因为两者都在 * 的同一侧。编译器会忽略额外的 const 限定符。你可以写成 char const const const const const*ptr = &a;,这与 char const *ptr = &a; 相同,意思是:

pointer to constant character

如果我们把它改成
char const * const ptr = &a;

这意味着:

constant pointer to constant char

您的代码段将停止编译:https://godbolt.org/z/sM9qnv8fq 例子:
- const int *ptr; - 指向常量整数的指针 - int * const ptr; - 常量指针,指向整数 - const int * const ptr; - 常量指针,指向常量整数
您的第一个示例static char const *const delimit_method_string[]声明:
static array of constant pointers to constant character

顺便说一下,我个人更喜欢在类型之前添加第一个const,即:

static const volatile char *const delimit_method_string[]

const char *p


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接