在解释和创建函数参数的类型时,我很难理解为什么C++比C更"放松"的行为.
C做世界上最简单的事情,它坚持你写的东西就是这样,另一方面,C++以一种我无法理解的扭曲方式运作.
例如,流行的argv
是一个char* []
传递给函数的时候变成了char**
,我真的不明白为什么,我期待和"想要" char * const *
但是我得到了这种行为.
您还可以阅读PDF中讨论C和C++之间差异的文章,文章也以这句话结尾:
虽然C++在确定函数签名时会忽略参数声明中的顶级cv限定符,但它并不完全忽略这些cv限定符.
因为我在网上找不到这个问题(嵌入式系统编程 - 2000年2月,这个老问题是免费的),我想知道这句话可能意味着什么.
有人可以解释为什么这种行为是它在C++中的行为?
编辑:
我的一个例子是
#includevoid foo(int argc, const char *const *const argv) { printf("%d %s\n", argc, argv[0]); } int main(int argc, char *argv[]) { foo(argc, argv); return (0); }
如果你编译它,gcc 4.8.1
你得到预期的错误
gcc cv_1.c cv_1.c: In function ‘main’: cv_1.c:8:3: warning: passing argument 2 of ‘foo’ from incompatible pointer type [enabled by default] foo(argc, argv); ^ cv_1.c:3:6: note: expected ‘const char * const* const’ but argument is of type ‘char **’ void foo(int argc, const char *const *const argv) { ^
此输出隐含了argv
被解释为的事实char**
函数参数可以通过值或引用传递.在引用的情况下,没有顶级限定符,因此我们可以忽略该情况.
对于按值参数,顶级限定符仅影响副本,并且完全独立于用于复制构造该参数的原始值.如果未从签名中删除顶级限定符,则以下两个函数将是有效且不同的重载:
void f(int i); void f(int const i);
现在的问题是,如果f(1)
应该选择两个重载中的哪一个?这里的问题是参数是否为const不会影响它的构造,因此编译器永远无法解析哪个是正确的重载.解决方案很简单:在签名中,顶级限定符被删除,两者都是相同的函数.
您链接的PDF文章包含许多关于C和C++在处理顶级cv限定符时的差异的错误陈述.这些差异要么不存在,要么与本文所暗示的不同.
实际上,在确定函数签名和函数类型时,C和C++都有效地忽略了函数参数声明中的顶级cv限定符.C和C++语言标准中的措辞(以及底层机制)在概念上可能不同,但最终结果在两种语言中都是相同的.
C++确实直接确定功能类型时对参数忽略顶层cv修饰符,如在8.3.5/5描述:"生产参数类型的列表之后,修改的参数类型的任何顶层CV-限定符删除时形成功能类型."
C不依赖于兼容类型的C特定概念,而是直接忽略此类限定符.它表示仅在参数的顶级cv限定符中不同的函数类型是兼容的,这对于所有方法和目的意味着它们是相同的.在6.7.5.3/15的函数类型的相容性的定义表示:"以类型兼容性和复合型的确定,[...]与限定的类型声明的每个参数取为具有不合格其声明的类型的版本".
链接的PDF文章指出,在C中,以下声明序列是非法的
void foo(int i); void foo(const int i);
实际上它在C语言中是完全合法的.C只需要在同一范围内的同一实体的所有声明都使用兼容类型(6.7/4).上面的两个声明是兼容的,这意味着它们只是合法地重新声明相同的功能.(在C++中,上述声明也是合法的,它们也重新声明了相同的功能.)
对于其他示例,在C和C++中,以下初始化有效
void foo(const int i); void bar(int i); void (*pfoo)(int) = foo; // OK void (*pbar)(const int) = bar; // OK
同时,在确定函数参数的局部变量类型时,C和C++ 同样考虑了顶级cv限定符.例如,在C和C++中,以下代码都是格式错误的
void foo(const int i) { i = 5; // ERROR! }
在C和C++中,在其参数上使用一个顶级cv限定声明的函数可以稍后使用其参数的完全不同的cv限定来定义.顶级cv资格的任何差异都不构成C++中的函数重载.
此外,您反复提到这char *[]
被解释为char **
相关的东西.我没有看到相关性.在函数参数列表中,T []
声明总是等同于T *
声明.但这与顶级cv-qualifiers完全无关.
同时,编辑中的代码示例无法编译,原因与顶级cv限定符无关.它不能编译,因为有一个从没有隐式转换char **
到const char *const *
C语言编写.请注意,此转换不涉及任何顶级cv限定符,也不关心任何顶级cv限定符.const
影响此转换的限定符仅出现在第一个和第二个间接层上.
这确实涉及C和C++之间的差异.在C和C++中char **
,const char **
不允许隐式转换为to (例如,请参见此处).但是,C++允许隐式转换char **
,const char *const *
而C仍然没有.你可以在这里阅读更多相关信息.但请注意,在所有这些情况下,顶级cv限定符完全无关紧要.他们根本没有任何作用.