![](/img/trans.png)
[英]Please help me understand this syntax (implementing static assert in C++)
[英]Is there a way for me to help Clang Static Analyzer understand global constant objects?
背景:由于原因,我的代码喜欢以(非常轻量级的)类对象的形式从其函数返回成功/错误代码值。 这工作正常,但是我很难让 Clang Static 分析器了解发生了什么; 它的混乱导致它在分析我的程序时发出虚假的“未初始化值”警告。
这里有一些最小的示例代码来说明/重现(错误)行为:
// my_status_t_class.h
#ifndef MY_STATUS_T_CLASS_H
#define MY_STATUS_T_CLASS_H
class status_t
{
public:
status_t(int errorNumber) : _errorNumber(errorNumber) {/* empty */}
bool IsError() const {return (_errorNumber != 0);}
private:
int _errorNumber;
};
// A list of some common error codes
const status_t STATUS_NO_ERROR(0);
const status_t STATUS_DATA_NOT_FOUND(-1);
// [...]
#endif
// my_test_program.cpp
#include <stdio.h>
#include <stdlib.h>
#include "my_status_t_class.h"
status_t GetValue(int & ret)
{
if (rand()%2)
{
ret = 5;
return STATUS_NO_ERROR;
}
else return STATUS_DATA_NOT_FOUND;
}
int main(int argc, char ** argv)
{
int ret;
if (GetValue(ret).IsError()) ret = 5;
printf("ret=%i\n", ret);
return 0;
}
当我在上面的代码上运行scan-build
时,它给出了这个 output:
$ scan-build g++ -std=c++17 my_test_program.cpp
scan-build: Using '/Users/jaf/llvm-project/build/bin/clang-16' for static analysis
testhashtable.cpp:20:8: warning: 2nd function call argument is an uninitialized value [core.CallAndMessage]
printf("ret=%i\n", ret);
^~~~~~~~~~~~~~~~~~~~~~~
生成 1 个警告。
.... 它会生成有关错误的报告,可以在此链接中查看。
正如您从报告中看到的那样,ClangSA 似乎认为我的GetValue()
function 有可能返回STATUS_DATA_NOT_FOUND
,但随后IsError()
方法在main()
内部返回 false,当ret
局部变量未定义时用来。
实际上,这是不可能的IsError()
将返回 true,因此main()
将执行ret = 5;
因此,当我将ret
传递给printf()
时,它始终具有明确定义的值。
我的问题是,这是 ClangSA 中的错误吗? 或者,如果没有,是否有推荐的方法让我在此处让 ClangSA 理解/遵循我的status_t
class 的语义? (看起来应该可以,因为代码都在my_status_t_class.h
header 文件中定义,ClangSA 可以直接访问该文件)。
我确实注意到,如果我用#define
声明替换my_status_t_class.h
中的常量声明,我会得到我想要的行为,例如,如果我这样做:
// my_status_t_class.h
[...]
// A list of some common error codes
#define STATUS_NO_ERROR status_t(0)
#define STATUS_DATA_NOT_FOUND status_t(-1)
// [...]
...然后 ClangSA 不会产生虚假警告...但这当然是一个非常丑陋的解决方案,如果有更好的选择,我想避免使用它。
我认为问题在于分析器无法看到STATUS_DATA_NOT_FOUND
object 始终是一个错误,因此不能确定ret
将始终被初始化。
它看不到的原因是因为STATUS_DATA_NOT_FOUND
object 不是常量表达式,所以分析器无法在编译时知道它的值。
解决此问题的一种方法是使用constexpr
构造函数使STATUS_DATA_NOT_FOUND
object 成为常量表达式:
class status_t
{
public:
constexpr status_t(int errorNumber) : _errorNumber(errorNumber) {/* empty */}
constexpr status_t STATUS_DATA_NOT_FOUND(-1);
通过该更改,分析器应该能够看到STATUS_DATA_NOT_FOUND
始终是一个错误,因此它将知道ret
将始终被初始化。
或者,您可以使STATUS_DATA_NOT_FOUND
object 成为全局变量而不是常量 object,并使用常量表达式对其进行初始化:
status_t STATUS_DATA_NOT_FOUND = status_t(-1);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.