我跟踪this question关于char[]
和char*
差异时出现了以下观察结果。
#include <iostream>
typedef char ar[];
typedef char* pr;
void f2(ar x, pr y)
{
std::cout << std::is_same<decltype(x), decltype(y)>::value << '\n';
std::cout << std::is_same<ar, pr>::value << '\n';
}
int main()
{
char data[] = "data";
char *ptr = data;
f2(data,ptr);
return 0;
}
输出(在Apple LLVM 4.2版(clang-425.0.28)上)
1
0
为什么这些报告的类型不同,但{1}不同?我怀疑它们实际上是由于decltype()
声明而不同的类型,但是为什么变量报告为相同的类型?
答案 0 :(得分:20)
在C ++中,与C一样,声明为数组类型的参数已调整(在编译时)为指针类型,特别是指向数组元素类型的指针。
无论是直接指定数组类型还是通过typedef指定数组类型,都会发生这种情况(请记住,typedef不会创建新类型,只是现有类型的别名)。
所以这个:
typedef char ar[];
typedef char* pr;
void f2(ar x, pr y)
{
// ...
}
真的意味着:
void f2(char* x, char* y)
{
// ...
}
C和C ++共享的另一个规则是,在大多数但不是所有上下文中,数组类型的表达式隐式地转换到指向数组对象的第一个元素。这意味着如果你定义一个数组对象:
char arr[10];
您可以使用该对象的名称作为带有char*
参数(丢失边界信息)的函数的参数。
在C中,隐式转换不发生的情况是:
sizeof
的操作数时(sizeof arr
产生数组的大小,而不是指针的大小); &
的操作数时(&arr
是一个指向数组的指针,而不是一个指向指针的指针);和char s[] = "hello";
将s
初始化为数组,而不是指针)。这些情况(或C ++中出现的其他情况)都不会出现在你的程序中,所以你的电话:
f2(data,ptr);
将char*
类型的两个指针值传递给f2
。
在f2
内,参数对象x
和y
都属于char*
,因此std::is_same<decltype(x), decltype(y)>::value
为真。
但ar
和pr
类型不同。 ar
是一个不完整的数组类型char[]
,pr
是指针类型char*
。
这解释了你的程序的输出。之所以出现这种奇怪,是因为您使用数组类型x
定义的参数ar
实际上是char*
类型,与pr
的类型相同。
答案 1 :(得分:2)
C系列是按值传递,数组的C值是指向其第一个元素的指针。当你将一个声明为数组的项传递给一个函数时,实际传递的是那个指针,而C将原型视为你那样声明它。
答案 2 :(得分:1)
我更改了代码,以便我们可以看到调用f2如何更改类型。在调用之前,变量是不同类型的。通话结束后,他们变得相同
typedef char ar[];
typedef char* pr;
void f2(ar x, pr y)
{
cout << is_same<decltype(x), decltype(y)>::value << '\n'; //same type
}
int main()
{
ar data = "data";
pr ptr = data;
cout << is_same<decltype(data), decltype(ptr)>::value << '\n'; // different
f2(data,ptr);
return 0;
}
输出是 0 0 。如@jthill,@ Dyp和@keith Thompson所说,这是因为数组衰减为指针。