const char* const* p 参数在 g++ 中编译但不是 gcc
Posted
技术标签:
【中文标题】const char* const* p 参数在 g++ 中编译但不是 gcc【英文标题】:const char* const* p param compiled in g++ but not gcc 【发布时间】:2021-12-27 22:48:32 【问题描述】:我有以下程序在 g++ 中编译得很好,但在 gcc 中编译得不好。
g() 接受一个指向 char* 数组的指针,并且不应修改 p 指向的任何内容。
无论如何要让它在 C 中正常工作?
% cat t.c
void g(const char* const* p)
int main()
char** p = 0;
g(p);
% g++ t.c
% gcc t.c
t.c: In function ‘main’:
t.c:5:5: warning: passing argument 1 of ‘g’ from incompatible pointer type [-Wincompatible-pointer-types]
g(p);
^
t.c:1:6: note: expected ‘const char * const*’ but argument is of type ‘char **’
void g(const char* const* p)
^
%
【问题讨论】:
C++
和 C
是不同的语言。在 C 中,*const
使其在嵌套指针类型中不兼容。
【参考方案1】:
错误消息会告诉您需要了解的所有信息。使 p 与 g 的参数具有相同的签名。
const char* const* p = 0;
但是,如果您需要 p 指向的任何内容都是只读的,那么这种类型规范就足以分配 p 和 g 参数(尽管可以更改数组指向的任何内容):
char* const* p = 0;
【讨论】:
换句话说,我需要在 C 中转换,而不是在 C++ 中。 @cktan 是的,您可以在调用 g 时强制转换 p 并将 p 声明保持原样。【参考方案2】:C 中的情况
在 C 中,限定符只允许隐式添加到最顶层的指针级别:
6.3.2.3 指针
2 对于任何限定符 q,指向非 q 限定类型的指针可以转换为指向 该类型的 q 限定版本;存储在原始指针和转换指针中的值 应该比较相等。
所以你只能隐式地将 const 添加到最顶层的指针,例如:
char** p = 0;
char* const* other = p; // ok
const char** other = p; // not ok: adding const not at top-level
这样做的原因是,如果您跳过几个环节,它将允许您获得指向 const 值的非 const 指针:
const char c = 'C';
char* ptr;
const char **ptrPtr = &ptr; // this is not legal
*ptrPtr = &c;
乍一看,这段代码看起来很合理——你有指向ptr
的ptrPtr
指向c
。
问题是您现在可以通过ptr
修改c
(这是非 const-qualified),例如:
*ptr = 'X'; // will change c
Here's an FAQ entry about this 如果您想了解更多相关信息。
如果你想使用显式强制转换,你仍然可以强制它:
void g(const char* const* p)
int main()
char** p = 0;
g((const char* const*)p);
C++ 中的情况
C++ 在可以隐式添加多少常量方面更为宽松。
7.3.6 Qualification conversions
(1)类型 T 的限定分解是一个序列 cvi 和 Pi 使得 T 是 “cv0 P0 cv1 P1 … cvn-1 P n−1 cvn U” 对于 n ≥ 0, 其中每个 cvi 是一组 cv 限定符([basic.type.qualifier]),每个 Pi 是“指向”([dcl.ptr] )、“指向类型 Ci 的成员的指针”([dcl.mptr])、“Ni 的数组”或“未知边界的数组” ([dcl.array])。如果 Pi 指定一个数组,则元素类型上的 cv 限定符 cvi+1 也被视为 cv 限定符 cvi数组。
(2) 两个类型 T1 和 T2 是相似的,如果它们具有具有相同 n 的限定分解,使得对应的 Pi 分量相同或一个是“array of Ni”,另一个是“array of unknown bound of”,U表示的类型相同。
(3)两种类型T1和T2的限定组合类型是与T1相似的类型T3,其限定分解为:
(3.1) 对于每一个 i > 0,cv3i 是 cv1i 的并集 和 cv2i, (3.2) 如果 P1i 或 P2i 是“数组of unknown bound of”,P3i 为“未知边界数组”,否则为 P1i子>,和 (3.3) 如果结果 cv3i 不同于 cv1i或 cv2i,或生成的 P3i 与 P1不同>i 或 P2i,然后将 const 添加到每个 cv3k 为 0其中 cvji 和 Pji 是 Tj.
这基本上归结为:
您始终可以将 const 添加到顶层 如果将 const 添加到较低级别,则从该级别开始的所有级别也必须是 const这个“const-propagation”对于避免出现在 C 中的极端情况是必要的:获取指向 const 对象的非常量指针。
几个例子:godbolt
int i = 1;
int* ip = &i;
int** ipp = &ip;
int*** ippp = &ipp;
const int* t1 = ip; // ok
const int* const* t2 = ipp; // ok
const int* const* const* t3 = ippp; // ok
// const int** t4 = ipp; // not ok
// const int*** t5 = ippp; // not ok
// const int* const** t6 = ippp; // not ok
int* const* t7 = ipp; // ok
int* const* const* t8 = ippp; // ok
// int* const** t9 = ippp; // not ok
结论
这就是为什么你的代码用 g++ 编译但不能用 gcc 编译的原因:
C++ 允许您为多个指针级别隐式添加 const 限定符(只要您遵循上述 da 规则),而 C 仅允许您将 const 隐式添加到***指针。
【讨论】:
以上是关于const char* const* p 参数在 g++ 中编译但不是 gcc的主要内容,如果未能解决你的问题,请参考以下文章
C++标准库 如何连接两个const char *类型字符串,并返回const char * 类型结果?
深入理解const char*p,char const*p,char *const p,const char **p,char const**p,char *const*p,char**cons(示例