为什么char []和char *作为typedef不同,但有时......不是?

时间:2013-09-05 00:55:28

标签: c++ decltype

我跟踪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()声明而不同的类型,但是为什么变量报告为相同的类型?

3 个答案:

答案 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中,隐式转换不发生的情况是:

  1. 当数组表达式是sizeof的操作数时(sizeof arr产生数组的大小,而不是指针的大小);
  2. 当数组表达式是一元&的操作数时(&arr是一个指向数组的指针,而不是一个指向指针的指针);和
  3. 当数组表达式是用于初始化数组类型对象的字符串文字时(char s[] = "hello";s初始化为数组,而不是指针)。
  4. 这些情况(或C ++中出现的其他情况)都不会出现在你的程序中,所以你的电话:

    f2(data,ptr);
    

    char*类型的两个指针值传递给f2

    f2内,参数对象xy都属于char*,因此std::is_same<decltype(x), decltype(y)>::value为真。

    arpr类型不同。 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所说,这是因为数组衰减为指针。