为什么C不允许从char**到const char*const*(和C++)的隐式转换?

ner*_*ert 15 c c++ gcc const clang

我知道,从隐式转换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;
}
Run Code Online (Sandbox Code Playgroud)

如果我将其编译为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)
 ^
Run Code Online (Sandbox Code Playgroud)

铛:

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)
                        ^
Run Code Online (Sandbox Code Playgroud)

这两种行为都是标准无关的,也是独立于编译器的.我试着用这两种不同的标准gccclang.

这项调查有两个原因.首先,我想了解是否有差异,其次,我有什么都不做与指针的任何层的功能,我需要它能够与合作const char **,以及char *const *char **.显式地转换每个调用是不可维护的.我不知道函数原型应该怎么样.


这是引起我好奇心的问题: 从char**隐式转换为const char**

以下是该char ** => const char**问题的另一个很好的解释:http: //c-faq.com/ansi/constmismatch.html

如果链接与此问题相关,请随意编辑它们.

ric*_*ici 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 P0cv0T cv'n Pn-1cv'n-1 … P1cv'1 P0cv'0

(where T是一个类型; 是指针/数组类型构造函数,每个都是一些可能是空的子集和)P1…Pncv0…cvnconstvolatile

规定:

  1. 对于每一个k > 0,是一个子集(所以你不能删除a 或a ),和cvkcv'kconstvolatile

  2. 如果和有些不同,以下所有内容包括.cvkcv'kk > 0cv'i>kconst

在实际标准中,这种表达方式是相反的; 我把它放在声明的顺序,而在标准中它是按指针/数组构造函数的应用顺序.但是,我没有改变编号的方向,这就是为什么它们从右到左编号.我也省略了一些细节 - 例如,两者T的相同并不是绝对必要的- 但我认为它给出了意图的概念.

对第一个限制的解释是相当明显的.第二个限制可以防止C FAQ中描述的问题,其中const指针可能存储在非const指针对象中,然后用于改变const它指向的对象.

底线是,在C++中,你的原型const char *const * param将与参数类型的工作char**,const char**或甚至char*const*,但在C只有最后一个没有预警的工作,它是最有用的.我所知道的唯一解决方法(除了切换到C++之外)就是忽略警告.

对于它的价值,在Posix规范exec*的基本原理部分中有一个关于这些原型引起的问题接口的注释,以及Posix选择的解决方法,它char*[]用作原型和文本说明这些是常量:(重点补充)

包含有关argv[]envp[]成为常量的语句,以明确未来的语言绑定编写者,这些对象是完全不变的.由于ISO C标准的限制,不可能在标准C中陈述该想法.为exec函数和参数指定两个级别的const资格似乎是自然的选择,因为这些函数不是修改指针数组或函数指向的字符,但这将禁止现有的正确代码.相反,只有指针数组被标记为常量.argv[]envp[]

在该段落之后有一个有用的兼容性图表,由于此站点的格式限制,我没有引用该图表.

  • @Olaf:橙子比苹果含有更多的维生素C. 苹果有更多的纤维. (19认同)
  • @Olaf:问题要求比较.我在比较.你不必喜欢比较. (17认同)
  • C和C++是**不同的**语言,而不仅仅是在这方面.比较苹果和橘子. (2认同)