我总是认为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
,我也不会收到任何警告。
答案 0 :(得分: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是一个非常令人困惑的主题。
当我们有const 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*
。
答案 1 :(得分:1)
分配有效的原因与以下分配有效的原因相同。
A --> root component
B
C
D // my component is here (4 levels of nesting)
此规则 1 解释说,如果两个操作数都是指针类型,则左指针所指向的类型必须具有与右指针所指向的类型相同的限定符。
右操作数是指向没有任何限定符的类型的指针。此类型是类型指向const char(const char** arr = malloc(10 * sizeof(const char *));
void* p = arr;
)的类型指针。不要让const限定符混淆你,那个限定符不属于指针类型。
左操作数是一个指向一个也没有任何限定符的类型的指针。类型无效。所以作业是有效的。
如果指针指向具有限定符的类型,则赋值将无效:
const char*
右操作数是指向具有限定符const的类型的指针,此类型是指向const char(const char* const* arr = malloc(10 * sizeof(const char *));
void* p = arr; //constraint violation
)的类型const指针。
左操作数是指向没有任何限定符的类型的指针,此类型为void类型。赋值违反约束 1 。
1 (引自:ISO / IEC 9899:201x 6.5.16.1简单分配约束1)
左操作数具有原子,限定或非限定指针类型,并且(考虑到
左值操作数在左值转换后将具有的类型)一个操作数是一个指针
到对象类型,另一个是指向合格或非限定版本的指针
void,左边指向的类型具有指向的类型的所有限定符
在右边;