我有以下程序.

#include <stdio.h>

int main(int argc, char const * const argv[], char const * const * envp) {
    for (int i = 0; i < argc; i++) {
        printf("argv[%d]: %s\n", i, argv[i]);
    }
    printf("\n");

    for (int i = 0; *envp != NULL; i++, envp++) { 
        printf("envp[%d]: %s\n", i, *envp);
    }

    return 0;
}

这将按照预期进行编译,不会出现任何警告.

如果我将envp指针改为常量,则将其声明更改为以下内容.

char const * const * const envp

则编译失败,如下所示.

$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:9:45: error: increment of read-only parameter ‘envp’
    9 |     for (int i = 0; *envp != NULL; i++, envp++) {
      |    

这对我来说是有意义的:在这个程序中,我们可以声明每个环境字符串的(第一个也是唯一一个?)字符值是一个常量,我们可以声明每个指向每个环境字符串的指针都是常量,但我们不能声明char**envp是常量.

现在,我的问题是,我如何以类似的方式将数组变量argv声明为常量,从而使argv不能被重新赋值?

也就是说,我想以这样一种方式声明argv:下面的代码将产生与上面的"read-only parameter ‘envp’"错误类似的编译错误.我希望以下代码不能编译.按照原样,将编译以下代码.

#include <stdio.h>

int main(int argc, char const * const argv[], char const * const * envp) {
    char const * const argvbad[1] = { NULL };
    argv = argvbad; // I want this to be impossible

    for (int i = 0; i < argc; i++) {
        printf("argv[%d]: %s\n", i, argv[i]);
    }
    printf("\n");

    for (int i = 0; *envp != NULL; i++, envp++) { 
        printf("envp[%d]: %s\n", i, *envp);
    }

    return 0;
}

这是一个关于一般数组变量的问题.我想学习如何将数组变量声明为常量,以便它们引用的数组不能重新赋值.

推荐答案

在参数声明中,可以使用括号内的限定符(如const[])来声明数组:

void foo(const char * const argv[const]) { … }

当声明被自动调整为使声明的标识符成为指针时,将对其应用限定符.以上相当于void foo(const char * const * const argv).

请注意,int main(int argc, char const * const argv[], char const * const * envp)通常不适合main,因为C标准在C 2018 5.1.2.2.1 1中指定了main的声明应该采用的形式.它的规范很灵活,因为它允许实现接受附加的形式,但我不知道有任何实现文档记录main可能具有该形式,以及附加的限定符.

另一个复杂之处在于,参数上的限定符直接与函数兼容性无关.例如,以下是兼容的声明:

void foo(int *p);
void foo(int * const p);

这是因为C 2018 6.7.6.3 15表示:

…(在确定类型兼容性和复合类型时,使用函数或数组类型声明的每个参数被视为具有调整后的类型,使用限定类型声明的每个参数被视为具有其声明类型的非限定版本.)

然而,它们将不兼容:

void foo(int *p);
void foo(const int *p);

因为上面的段落只适用于参数上直接的限定符.这增加了int main(int argc, char *argv[const])是C 2018 5.1.2.2.1 1中main的令人满意的声明的可能性,因为它与int main(int argc, char *argv)兼容,因此可能满足其允许的"同等"声明.

C++相关问答推荐

丑陋的三重间接:可扩展的缓冲区管理 struct

在C中使用动态内存分配找到最小的负数

自定义应用程序上的日志(log)轮换问题

C:二进制搜索和二进制插入

这是一个合法的C Strdup函数吗?

如何使用低级C++写出数值

是否所有C编译器在将浮点数转换为整型数时都会隐式删除小数?

struct 上的OpenMP缩减

_泛型控制表达式涉及数组碰撞警告的L值转换错误?

为什么该函数不将参数值保存到数据 struct 中?

轮询libusb_pollfd struct 列表的正确方式是什么?

是否可以通过调用两个函数来初始化2D数组?示例:ARRAY[STARTING_ROWS()][STARTING_COLUMNS()]

如何按顺序将所有CSV文件数据读入 struct 数组?

I2C外设在单次交易后出现故障

不同原型的危险C函数是可能的

Go和C中的数据 struct 对齐差异

我错误地修复了一个错误,想了解原因

将数组中的所有元素初始化为 struct 中的相同值

如何找出C中分配在堆上的数组的大小?

const struct 成员的 typedef 中的灵活数组大小