C语言 常量字符串动态数组的正确类型



我一直觉得const char **x是用于动态分配的常量字符串数组的正确类型,如下所示:

#include <stdlib.h>
int main()
{
const char **arr = malloc(10 * sizeof(const char *));
const char *str = "Hello!";
arr[0] = str;
free(arr);
}

但是,当使用VS2017编译此代码时,我在free行收到此警告:

warning C4090: 'function': different 'const' qualifiers

我的代码有问题吗?FWIW,当我使用 GCC 编译时,即使使用-Wall -Wextra -pedantic也没有收到任何警告.

你的代码没有错。这方面的规则可以在C标准中找到:

6.3.2.3 指针 指向
void 的指针可以转换为指向任何对象类型的指针,也可以从指向任何对象类型的指针转换为指针。指向任何对象类型的指针可以是 转换为指向 void 的指针,然后再次返回;结果应 与原始指针相等。

对于任何限定符 q,指向非 q 限定类型的指针可以是 转换为指向类型的 q 限定版本的指针;这 存储在原始指针和转换指针中的值应进行比较 平等。

这意味着任何指向对象类型(指向变量)的指针都可以转换为 void 指针,除非指针是限定的(常量或易失性)。所以做得很好

void* vp; 
char* cp; 
vp = cp;

但这是不行的

void* vp; 
const char* cp; 
vp = cp; // not an allowed form of pointer conversion

目前为止,一切都好。但是,当我们混合指针到指针时,const-ness是一个非常令人困惑的主题。

当我们有一个const char** arr时,我们有一个指向常量字符的指针(提示:从右到左读取表达式)。或者在 C 标准乱码中:指向类型限定指针的指针。 不过,arr本身并不是一个合格的指针!它只指向一个。

free()期望一个指向 void 的指针。我们可以将任何类型的指针传递给它,除非我们传递一个合格的指针。const char**不是一个合格的指针,所以我们可以很好地传递它。

char* const*

限定指针指向指向类型的指针。

请注意,当我们尝试这样做时,gcc 是如何抱怨的:

char*const* arr = malloc(10 * sizeof(char*const*));
free(arr);

gcc -std=c11 -pedantic-errors -Wall - Wextra

错误:"免费"的传递参数 1 会丢弃"const"限定符 指针目标类型

显然,Visual Studio给出了不正确的诊断。或者,您将代码编译为 C++,这不允许与void*进行隐式转换。

分配有效的原因与以下分配有效的原因相同。

const char** arr = malloc(10 * sizeof(const char *));
void* p = arr;

此规则1说明,如果两个操作数都是指针类型,则左指针指向的类型必须与右指针指向的类型具有相同的限定符。

右操作数是指向没有任何限定符的类型的指针。此类型是指向常量字符 (const char*) 的类型指针。不要让常量限定符混淆您,该限定符不属于指针类型。

左操作数是一个指针,指向也没有任何限定符的类型。类型为空。因此,分配是有效的。

如果指针指向具有限定符的类型,则赋值将无效:

const char* const* arr = malloc(10 * sizeof(const char *));
void* p = arr;    //constraint violation

右操作数是指向具有限定符 const 的类型的指针,此类型是指向 const 字符 (const char* const) 的类型 const 指针。

左操作数是一个指针,指向没有任何限定符的类型,此类型为 void。赋值违反了约束1


1(引自:ISO/IEC 9899:201x 6.5.16.1 简单赋值约束 1)
左操作数具有原子、限定或非限定指针类型,并且(考虑 左操作数在左值转换后将具有的类型)一个操作数是一个指针 指向对象类型,另一个是指向限定或非限定版本的指针 void,并且左边指向的类型具有指向的类型的所有限定符 靠右边;

相关内容

  • 没有找到相关文章

最新更新