翻译《有关编程、重构及其他的终极问题?》——31.在C-C++中数组不是值传递的

翻译《有关编程、重构及其他的终极问题?》——31.在C/C++中数组不是值传递的

标签(空格分隔):翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2017年08月14日


31.在C/C++中数组不是值传递的

下面这段代码摘自Wolf游戏项目。PVS-Studio分析器对这段代码的诊断结果为:V511 The sizeof() operator returns size of the pointer, and not of the array, in ‘sizeof (src)’ expression(译者注:sizeof()操作符返回的是指针的尺寸大小,而不是数组的)。

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );
}

解释
有时候,程序员们忘记了C/C++不可以通过值传递给函数传递数组,这是因为实际上把数组的指针作为一个参数传递了。数组后面方括号的数字其实没有意义,它们仅仅可以作为对程序员的提示,所以一般我们会把数组尺寸作为另外一个参数进行传递。事实上,你可以传递一个完全不同的尺寸,比如,下面的代码将会成功编译:

void F(int p[10]) { }
void G()
{
  int p[3];
  F(p);
}

对应的,sizeof(src)操作符计算的也不是数组的尺寸,而是指针的尺寸。结果,memcpy()将只拷贝数组中的部分数据。也就是说,4或者8字节,这依赖于指针的长度大小(没有考虑一些不常见的架构)。

正确的代码
最简单的纠正代码的方式可以如下:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy(mat, src, sizeof(float) * 3 * 3);
}

建议
有几个方法可以让你的代码更安全。

如果数组大小已知:你可以让函数使用数组的引用。但不是每个人知道可以这么做,并且知道怎么写个的人就更少了。所以我希望这个例子将会有趣和有用的:

ID_INLINE mat3_t::mat3_t( float (&src)[3][1] )
{
  memcpy( mat, src, sizeof( src ) );
}

现在,就有可能给一个函数传递正确大小的数组了。并且最重要的,sizeof()操作符将会计算数组的尺寸,而不是指针的。

还有另外一个解决这个问题的方式就是开始使用std:array类。

如果数组大小未知:一些编程书籍的作者建议使用std::vector类,以及其他类似的类,但实际来说这并不方便。

有时候你使用一个简单的指针,你应该传递两个参数给函数:一个指针和这个指针所指向元素的个数。然后,总体而言,这是不是好的实践,因为会导致很多bug。

类似这些例子,你可以在《C++核心编程向导》中找到一些有用且值得一读的思路。我还建议读读《不要把一个数组当成一个指针传递》这篇文章。当你有任何空闲时间时,应该首先读读《C++核心编程向导》,里面包含了很多有用的主意。

猜你喜欢

转载自blog.csdn.net/headman/article/details/77162206
今日推荐