【问题标题】:Why does argument matching in C++ ignore array sizes?为什么 C++ 中的参数匹配会忽略数组大小?
【发布时间】:2014-09-19 06:36:04
【问题描述】:

在本例中,getSize() 返回数组的大小。

template <class T, size_t N>
size_t getSize(T(&array)[N])
{
   return N;
}

虽然这段代码无法编译:

template <class T, size_t N>
size_t getSize(const T array[N])
{
   return N;
}

经过一些研究,我得出结论,这意味着 C++ 将允许这样的事情:

void func(char c[10]) {}

int main()
{
   char c[5];
   func(c);
}

这段代码在编译时甚至没有产生警告,这让我很吃惊。如果实现了数组大小检查,它将使代码更安全,并且第二个模板也可以编译并正常工作。 这种编译器行为背后的原因是什么?

【问题讨论】:

  • 因为 C++ 继承了 C 的语言设计错误,为了向后兼容而保留了它们。
  • @BenjaminLindley。编译器报告 C 程序尝试将 [5] 数组作为 [10] 数组传递的问题是什么?这不会破坏任何兼容性,而是有助于发现一些旧代码中的潜在错误。
  • 数组类型的参数实际上并不是数组类型。它是一个指针。
  • @bkxp 这是真的,我同意。但是从编译器的角度来看,函数参数char c[10] 完全等同于char* c,并且仅用于文档目的。该函数需要一个指针,仅此而已。应该避免这种“成语”。
  • @Benjamin Lindley。如果是这样,那么第一个模板也不起作用。但它返回数组的大小就好了。

标签: c++ arrays templates size


【解决方案1】:

像 C++ 中的许多其他东西一样,“因为 C 就是这样做的”。
(C 中的许多事情都是这样的,因为 B 或 BCPL 就是这样做的。)

在 C++ 中和在 C 中一样

void foo(int p[10]);

等价于

void foo(int p[]);

相当于

void foo(int *p);

也就是说,参数看起来像一个数组,但实际上是一个指针。
此函数的数组参数被隐式转换为指向其第一个元素的指针。

C 和 C++ 都允许您将 指针 传递给特定大小的数组,像这样

void foo(int (*p)[10]);

// ...
int a[10];
int b[20];
int *c;
foo(&a); // OK
foo(&b); // Not OK
foo(c);  // Not OK

C++ 对一个特定大小的数组的引用,您的模板使用该数组。

【讨论】:

  • 感谢您的解释!有这么多“弃用”警告,典型的 C++ 编译器会针对潜在的不安全事物发出警告,我希望它至少会警告参数中的数组大小不匹配。
  • 为了在这片混乱的海洋中再添一滴,在void foo(T t[42]); 中对于用户定义的T,C 和C++ 之间实际上存在差异。虽然签名相同,但事实证明 C 需要一个完整的类型!
  • @juanchopanza 这很奇怪。这是对 C 的现代补充吗?
  • 显然不是。我已经在std=c89 模式下使用 gcc 和 clang 对其进行了测试。我很惊讶地发现这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多