【问题标题】:Why C doesn't allow implicit conversion from char ** to const char *const * (and C++ does)?为什么 C 不允许从 char ** 到 const char *const * 的隐式转换(而 C++ 允许)?
【发布时间】:2016-02-10 15:55:10
【问题描述】:

我知道从 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)
                        ^

这两种行为都独立于标准,也独立于编译器。我尝试了gccclang 的各种标准。

这个查询有两个原因。首先,我想了解是否有区别,其次,我有一个函数对指针的任何层都不做任何事情,我需要它能够与 const char ** 以及 char *const * 和 @987654334 一起使用@。显式转换每个调用是不可维护的。而且我不知道函数原型应该是什么样子。


这是引发我好奇心的问题: Implicit conversion from char** to const char**

这是char ** =&gt; const char** 问题的另一个很好的解释: http://c-faq.com/ansi/constmismatch.html

如果与此问题相关的链接令人困惑,请随时将其编辑掉。

【问题讨论】:

  • 可以抑制无用的警告,在这种情况下使用-Wno-incompatible-pointer-types(用于gcc)和-Wno-incompatible-pointer-types-discards-qualifiers(用于clang)(这就是警告消息显示激活它的警告标志的原因:所以如果它对你没有用,你可以压制它)。然后你可以继续-Werror 没有问题。
  • @chrisjester-young 这不是他的问题如何抑制警告。
  • C 有一个更简单、更不灵活的类型系统。 C++ 有更强大的类型系统。就这样。 C 不能 允许这种转换没有技术原因。它可以。它根本没有。
  • @Olaf 不,C++ 允许从 Foo** 转换为 const Foo* const*
  • @nert:“为什么?”的问题已经存在了很长时间。我也一直在寻找答案,但似乎这里唯一的答案是“它只是历史上发生的,没有人关心纠正这个问题”。我不知道为什么 C 不想在这种转换中采用 C++ 方法来实现 const 正确性。它不会破坏任何遗留代码。

标签: c++ c gcc clang constants


【解决方案1】:

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 cv<sub>n</sub> P<sub>n-1</sub>cv<sub>n-1</sub> … P<sub>1</sub>cv<sub>1</sub> P<sub>0</sub>cv<sub>0</sub>T cv'<sub>n</sub> P<sub>n-1</sub>cv'<sub>n-1</sub> … P<sub>1</sub>cv'<sub>1</sub> P<sub>0</sub>cv'<sub>0</sub>

(其中T 是一个类型;P<sub>1</sub>…P<sub>n</sub> 是指针/数组类型构造函数,每个cv<sub>0</sub>…cv<sub>n</sub> 可能是constvolatile 的某个空子集)

前提是:

  1. 对于每个k &gt; 0cv<sub>k</sub>cv'<sub>k</sub> 的子集(因此您不能删除constvolatile),并且

  2. 如果cv<sub>k</sub>cv'<sub>k</sub> 对于某些k &gt; 0 不同,则以下所有cv'<sub>i&gt;k</sub> 都包括const

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

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

底线是,在 C++ 中,您的原型 const char *const * param 将与 char**const char** 甚至 char*const* 类型的参数一起使用,但在 C 中,只有最后一个可以在没有警告的情况下工作,而且它是最没用的。我知道的唯一解决方法(除了切换到 C++)是忽略警告。

对于它的价值,Rationale section of the Posix specification of the exec* interfaces 中有一条关于这导致这些原型的问题的注释,以及 Posix 选择的解决方法,即使用 char*[] 作为原型并在文本上注明这些是不变的: (强调)

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

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

【讨论】:

  • @Olaf:这个问题要求进行比较。我在比较。您不必喜欢这种比较。
  • @Olaf:橙子比苹果含有更多的维生素 C。苹果含有更多的纤维。
  • 递归 C++ 定义的原因可能是由于 const 引用的特殊属性,这种情况在 C++ 中更可能发生,因此需要在那里处理。
  • C 和 C++ 是不同的语言,但它们仍然密切相关,因为 C++ 被设计为能够直接包含标准 C 库头文件并调用其中定义的函数。
  • @nert:这对我来说已经足够了 :) 标准本身是收费的,但委员会免费提供草稿;最接近标准的草案通常仅在小的编辑更正上有所不同,这就是您将在此处看到的引用。对于 C:open-std.org/jtc1/sc22/wg14/www/standards(链接显示:WG14 N1570)对于 C++:isocpp.org/std/the-standard
猜你喜欢
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
  • 2021-11-01
  • 2017-03-03
  • 1970-01-01
  • 2011-10-24
相关资源
最近更新 更多