2

当参数被定义为比原型指定的更小的数组时,是否有任何工具(最好在 linux 上)可以发出警告?

例如:

void somefunc(float arg[10]);  /* normally this would be defined in a header */

void my_func(void)
{
    float arg[2];
    somefunc(arg);  /* <-- this could be a warning */
}

我意识到这不是无效代码,但如果可以发出警告,它可以解决一些常见错误(最近遇到了这些错误之一)。

一些工具(例如,clang 静态检查器)会警告函数是否在同一个文件中并在数组边界之外设置一个值,但我想知道如果 arg 小于原型本身,是否会有任何警告。

我使用过 cppcheck、clang、smatch、splint、gcc 的 -Wextra ......但没有人抱怨这一点。

4

4 回答 4

8

原型中的值对编译器没有意义,被忽略了!上面声明的函数等价于

void somefunc(float* arg);

void somefunc(float arg[]);

使用 C++ 时,您可以在编译时使用引用处理大小限制。如果你真的想要一个 10float的数组,你可以通过引用传递它,这将强制大小是正确的:

void somefunc(float (&arg)[10]);

但是,这将阻止传递更大的数组。如果要传递更大的数组,可以使用模板转发功能:

void somefunc_intern(float* arg);
template <int Size>
typename std::enable_if<(10 <= Size)>::type
somefunc(float (&arg)[Size]) {
    somefunc_intern(arg);
}

当然,如果传递的数组太小,这不会产生警告,而是会产生错误。

于 2012-10-04T06:19:59.747 回答
3

C语言中,float arg[10]参数数组的界限只是一种风格:它是给程序员的提示,而不是编译器。由于 C 具有弱类型检查,您可以将任何类型的浮点指针或数组传递给函数。有人可能会争辩说,在向函数传递参数之前没有阅读函数文档的程序员是在自找麻烦。但当然总是存在意外错误的可能性。

好的编译器会对此提出警告。如果你有一个糟糕的编译器,它不会发出警告,你确实应该考虑使用外部静态分析工具,它们总是对可疑的类型转换非常挑剔。Lint有一个 Linux 版本,我没有使用过它,但它被认为是大型复杂版本的经济实惠的替代品。

从理论上讲,您可以编写会导致编译器产生更多警告的代码,但它会混淆程序。我不会推荐它,它看起来像:

void somefunc(float (*arr_ptr)[10])
{
  float* arg = *arr_ptr;
  ...
}

int main()
{
  float ten[10];
  float two[2];

  somefunc(ten);  // warning
  somefunc(&ten); // warning
  somefunc(two);  // warning
  somefunc(&two); // warning

  float (*ten_ptr)[10] = &ten;
  float (*two_ptr)[2] = &two;

  somefunc(ten_ptr) // ok
  somefunc(two_ptr) // warning

}
于 2012-10-04T07:00:46.420 回答
1

自从提出这个问题以来,cppcheck 已根据我的建议添加了此功能(谢谢大家!),

提交: https ://github.com/danmar/cppcheck/commit/7f6a10599bee61de0c7ee90054808de00b3ae92d

问题:http: //sourceforge.net/apps/trac/cppcheck/ticket/4262

在撰写本文时,它还没有发布,但我认为它会在下一个版本中发布。

于 2012-12-22T08:41:59.217 回答
-1

std::array<N>如果您改用C 数组,一个完全普通的 C++ 编译器会给您一个编译错误。

所以就这么做?

于 2012-10-04T06:32:16.333 回答