我知道无法完成从char **
到const char **
的隐式转换以及为什么转换为char *const *
。请参见下文,了解相关说明的链接。
除了一件特别的事情外,这一切都是有道理的。所以我有以下代码:
#include <stdio.h>
void
print(const char *const*param)
{
printf("%s\n", param[0]);
}
int
main(int argc, char **argv)
{
print(argv);
return 0;
}
如果我将其编译为C ++代码,它编译得非常好。但是,如果相同的代码仅编译为C代码,我会收到错误(嗯,警告,但是假设-Werror
,即将警告视为错误。)
GCC
test.c: In function ‘main’:
test.c:12:11: warning: passing argument 1 of ‘print’ from incompatible pointer type [-Wincompatible-pointer-types]
print(argv);
^
test.c:4:1: note: expected ‘const char * const*’ but argument is of type ‘char **’
print(const char *const*param)
^
铛:
test.c:12:11: warning: passing 'char **' to parameter of type 'const char *const *' discards qualifiers in nested pointer types [-Wincompatible-pointer-types-discards-qualifiers]
print(argv);
^~~~
test.c:4:25: note: passing argument to parameter 'param' here
print(const char *const*param)
^
这两种行为都是标准无关的,也与编译器无关。我尝试了gcc
和clang
的各种标准。
这次调查有两个原因。首先,我想了解是否存在差异,其次,我有一个函数对指针的任何层都不起作用,我需要它能够使用const char **
以及{{1} }和char *const *
。显式地转换每个调用是不可维护的。我不知道函数原型应该怎么样。
这是引起我好奇心的问题: Implicit conversion from char** to const char**
以下是char **
问题的另一个很好的解释:
http://c-faq.com/ansi/constmismatch.html
如果链接与此问题相关,请随时编辑它们。
答案 0 :(得分:13)
C和C ++在这方面有所不同。我没有回答为什么C ++更慷慨,除了C ++行为在我看来是正确的。
C根本不允许间接const
转换。这是一个保守的,易于实施的限制,令人遗憾的是,您无法向期望char*[]
的函数提供char const* const*
。限制在§6.3.2.3第2段中,它根本不是递归的:
对于任何限定符
q
,指向非q
限定类型的指针可以转换为指向该类型的q
限定版本的指针;存储在原始指针和转换指针中的值应相等。
C ++允许根据§4.4[conv.qual]第3段中的某种复杂公式进行转换。允许转换
T cvn Pn-1cvn-1 … P1cv1 P0cv0
⇒
T cv'n Pn-1cv'n-1 … P1cv'1 P0cv'0
(其中T
是一种类型; P1…Pn
是指针/数组类型构造函数,每个cv0…cvn
都可能是const
和volatile
的空子集)
提供:
对于每个k > 0
,cvk
都是cv'k
的子集(因此您无法移除const
或volatile
),以及
如果某些cvk
的{{1}}和cv'k
不同,则以下所有k > 0
都包含cv'i>k
。
在实际标准中,该表达式是相反的;我把它放在声明的顺序,而在标准中它是按指针/数组构造函数的应用顺序。但是,我没有改变编号的方向,这就是为什么它们从右到左编号。我也省略了一些细节 - 例如,两个const
并不是完全相同的 - 但我认为它给出了意图的概念。
对第一个限制的解释相当明显。第二个限制可以防止C FAQ中描述的问题,其中T
指针可能存储在非const
指针对象中,然后用于改变它指向的const
对象到。
最重要的是,在C ++中,您的原型const
将使用const char *const * param
,char**
或甚至const char**
类型的参数,但在C中仅使用最后一个一个人会在没有警告的情况下工作,而且它是最不实用的。我所知道的唯一解决方法(除了切换到C ++之外)就是忽略警告。
对于它的价值,Rationale section of the Posix specification of the exec*
interfaces中有一个关于这些原型引起的问题的注释,以及Posix选择的解决方法,即使用char*const*
作为原型和文本注释这些是不变的:(强调添加)
包含有关
char*[]
和argv[]
为常量的语句,以便明确将来语言绑定的编写者使这些对象完全不变。 由于ISO C标准的限制,无法在标准C中声明该想法。指定envp[]
的两个级别 -const
和{{ exec函数的参数似乎是自然的选择,因为这些函数不会修改指针数组或函数所指向的字符,但这会禁止现有的正确代码。相反,只有指针数组被标记为常量。
该段落之后有一个有用的兼容性图表,由于此网站的格式限制,我没有引用它。