17

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

#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.

4

2 回答 2

6

您的代码没有任何问题。相关规则可在此处的 C 标准中找到:

6.3.2.3 指针
指向 void 的指针可以转换为指向任何对象类型的指针或从指向任何对象类型的指针转​​换。指向任何对象类型的指针都可以转换为指向 void 的指针并再次返回;结果应与原始指针比较。

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

这意味着任何指向对象类型(指向变量)的指针都可以转换为 void 指针,除非该指针是合格的(const 或 volatile)。所以这样做很好

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

但是这样做是不行的

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

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

当我们有 aconst char** arr时,我们有一个指向常量 char 的指针(提示:从右到左读取表达式)。或者在 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

错误:传递“free”的参数 1 会从指针目标类型中丢弃“const”限定符

显然,Visual Studio 给出了不正确的诊断。或者,您将代码编译为 C++,它不允许隐式转换到/从void*.

于 2017-03-23T07:34:20.847 回答
1

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

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

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

右操作数是指向没有任何限定符的类型的指针。这种类型是指向 const char ( const char*) 的类型指针。不要让那个 const 限定符混淆你,那个限定符不属于指针类型。

左操作数是一个指向同样没有任何限定符的类型的指针。类型为空。所以这个赋值是有效的。

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

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

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

左操作数是指向没有任何限定符的类型的指针,该类型为 void 类型。该分配违反了约束1


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

于 2017-03-23T09:24:13.433 回答