适用于const字符串动态数组的类型

And*_*Sun 17 c const visual-studio pointer-conversion

我一直认为这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);
}
Run Code Online (Sandbox Code Playgroud)

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

warning C4090: 'function': different 'const' qualifiers
Run Code Online (Sandbox Code Playgroud)

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

Lun*_*din 6

您的代码没有任何问题.这里的规则可以在C标准中找到:

6.3.2.3指针
指向void的指针可以转换为指向任何对象类型的指针.指向任何对象类型的指针可以转换为指向void的指针,然后再返回; 结果应该等于原始指针.

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

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

void* vp; 
char* cp; 
vp = cp;
Run Code Online (Sandbox Code Playgroud)

但这样做并不好

void* vp; 
const char* cp; 
vp = cp; // not an allowed form of pointer conversion
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.但是当我们混合使用指针指针时,const-ness是一个非常令人困惑的主题.

当我们有一个时const char** arr,我们有一个指向常量char的指针(提示:从右到左读取表达式).或者在C标准的乱码中:指向要键入的限定指针的指针.arr虽然本身不​​是一个合格的指针!它只指向一个.

free()期望指向void的指针.我们可以传递任何类型的指针,除非我们传递一个合格的指针.const char**不是一个合格的指针,所以我们可以通过它.

指向类型指针的限定指针char* const*.

注意当我们尝试这个时gcc如何抱怨:

char*const* arr = malloc(10 * sizeof(char*const*));
free(arr);
Run Code Online (Sandbox Code Playgroud)

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

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

显然,Visual Studio提供的诊断不正确.或者您将代码编译为C++,它不允许隐式转换void*.