C++ 为什么C不';不允许从char**隐式转换为const char*const*(C+;+;是否允许)?

C++ 为什么C不';不允许从char**隐式转换为const char*const*(C+;+;是否允许)?,c++,c,gcc,clang,constants,C++,C,Gcc,Clang,Constants,我知道从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(

我知道从
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;
}
叮当声:

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**
以及
char*const*
char**
。显式强制转换每个调用是不可维护的。我不知道函数原型应该是什么样子


这是引起我好奇心的问题:

下面是对
char**=>const char**
问题的另一个很好的解释:


< C++ >如果链接与此问题有关,请随意编辑。

< P> C和C++在这方面是不同的。我没有答案为什么C++更慷慨,除了C++行为似乎是正确的。 C根本不允许间接
const
转换。这是一个保守的、易于实现的限制,不幸的结果是,您无法为一个需要
char const*const*
的函数提供
char*[]
。该限制在§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
可能是
常量和
volatile
的一些空子集)

前提是:

  • 对于每个
    k>0
    cvk
    cv'k
    的子集(因此您不能删除
    const
    volatile
    ),以及

  • 如果
    cvk
    cv'k
    因某些
    k>0
    而不同,则以下所有
    cv'i>k
    包括
    const

  • 在实际标准中,该表达式是相反的;我把它放在声明的顺序上,而在标准中,它是按照指针/数组构造函数的应用顺序。我没有改变编号的方向,这就是为什么它们是从右向左编号的。我还遗漏了一些细节——例如,两个
    T
    s不一定完全相同——但我认为它给出了一个意图

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

    底线是,在C++中,您的原型<代码> const char * const *PARAM< /Calp>将使用类型<代码> char **/COD>、 CONTHARCHAR**/COD>,或者甚至 char *const */COD>,但是在C中,最后一个将不加警告地工作,并且它是最不有用的。我所知道的唯一解决方法(除了切换到C++)是忽略警告

    值得一提的是,在中有一条关于这些原型所导致的问题的注释,以及Posix选择的解决方法,即使用
    char*[]
    作为原型,并从文本上注意这些是恒定的:(强调添加)

    包含关于
    argv[]
    envp[]
    是常量的语句是为了向语言绑定的未来编写者明确说明这些对象是完全常量由于ISO C标准的限制,无法在标准C中说明这一想法。规定了两个级别的
    const
    -exec函数的
    argv[]
    envp[]
    参数的限定似乎是自然选择,假设这些函数既不修改指针数组,也不修改函数指向的字符,但这将不允许现有的正确代码。相反,只有指针数组被记为常量


    该段落后面有一个有用的兼容性图表,由于本网站的格式限制,我没有引用该图表。

    在本例中,
    -Wno不兼容指针类型
    (对于gcc)和
    -Wno不兼容指针类型丢弃限定符
    (对于clang)可以抑制无用的警告(这就是警告消息显示激活它的警告标志的原因:因此,如果它对您没有用处,您可以抑制它)你可以继续使用<代码> - Werror <代码>,没有问题。@克里斯捷斯特杨,他不该如何警告。C有一个更简单、更不灵活的类型系统。C++有一个更强大的类型系统。就这样。C为什么不能允许这个转换。没有。它可以。它不简单。@ Olaf No,C++允许从
    Foo**
    to
    const Foo*const*
    @nert:“为什么?”这个问题已经存在了很长时间。我也一直在寻找答案,但这里唯一的答案似乎是“历史上就是这样发生的”
    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)
                            ^