13

当我关注这个关于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

为什么这些报告为不同的类型,而不是不同decltype()的 s ?我怀疑它们实际上是由于它们的声明而不同的类型typedef,但是为什么变量报告为相同的类型?

4

3 回答 3

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为数组,而不是指针)。

这些情况(或 C++ 中发生的其他情况)都不会出现在您的程序中,因此您的调用:

f2(data,ptr);

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

在里面f2,参数对象xy都是 type char*,所以std::is_same<decltype(x), decltype(y)>::value是真的。

但类型arpr是不同的。ar是不完整的数组类型char[],并且pr是指针类型char*

这解释了您的程序的输出。奇怪的发生是因为x您使用数组类型定义的参数ar实际上是类型char*,与pr.

于 2013-09-05T01:44:22.410 回答
2

C 系列是按值传递的,数组的 C 值是指向其第一个元素的指针。当您将声明为数组的项传递给函数时,真正传递的是该指针,C 将原型视为您以这种方式声明它。

于 2013-09-05T01:29:52.283 回答
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 所说,这是因为数组衰减为指针。

于 2013-09-05T02:07:01.563 回答