1

我正在组织 Klocwork 规则并清除静态分析发现的任何问题。应用了多个规则,目前我在指定字符文字时遇到问题。让我们考虑这个例子:

for (const char* p = str; *p != '\0'; ++p)

如您所见,这是对 C-String 的循环迭代。它用于利用 constexpr 字符串文字的 unordered_map。性能测量证明,将它们存储为 std::string 会增加内存使用并由于开销而影响性能。由于此地图内容是恒定的,我正在使用 C-Strings 的自定义哈希函子(再次,以避免转换并将字符串复制到 std::string 只是为了生成哈希)。简单的答案是使用 std::string_view 但在此环境中不可用。所以问题来自条件本身。条件应检查字符是否以空值结尾。

显然,起初我使用!p它,因为标准保证终止 null 解析为 false(无论 char 的真实类型是什么)。它会导致 AUTOSAR C++14 (18-03) 错误MISRA.STMT.COND.NOT_BOOLEAN,转换为“ if 或循环语句的条件具有类型 'char' 而不是 'boolean' ”。

好的,然后我将其更改为显式比较p != 0,结果证明是MISRA.CHAR.NOT_CHARACTER违规行为,即“ 'char' is used for non-character value ”。

同样,这是有效的一点,因为我将 char 与 int 进行比较,但 char 既不是 int 也不是 unsigned int。因此我将其更改为*p != '\0'应该直接转换为空字符。这反过来又给出了MISRA.LITERAL.UNSIGNED.SUFFIX违规,即“无符号整数文字 ''\0'' without the 'U' suffix ”。现在我很惊讶。即使 char 在一个编译器中被认为是无符号的,也不能保证它是有符号的或无符号的,所以我不能将它硬编码为任何符号。甚至没有提到似乎没有办法为字符文字指定后缀。在我看来,它已经误报为'\0'IS char 类型,不需要任何进一步的转换或强制转换。这显示了更明显的语法问题,例如uri.find_last_of('/')我正在寻找特定的字符,而不是特定的价值。这种情况会产生同样的错误,抱怨我没有指定后缀。(uri 是 std::string)

我的猜测是,这是错误过滤器实现的误报。此外,似乎静态分析可能被错误配置,因为字符文字仅在 C 中被认为是整数,而不是在 C++ 中。

作为旁注,我将在第一个示例中补充说,使用*p != char(0)解决了这个问题,但这远非首选解决方案,并且只能与已知的字符整数值一起使用,这远不如使用文字灵活且容易出错,因此我不会使用此解决方法。

你对这个问题有什么看法?也许其他人已经遇到了这样的 Klocwork 错误并找到了解决方案,而不是为每个文字字符实例禁用规则或抑制它。我已经有了我的常见误报列表,这些误报通常来自 C++11 和更新的标准,由基于 MISRA 2008 C++ 的规则检查。

4

1 回答 1

2

显然,起初我使用 !p 因为标准保证终止 null 解析为 false

是的,但 MISRA 规则超出了标准。考虑类似的东西char* ptr = 0; if(ptr)。很容易在if(ptr)和之间打滑if(*ptr),这是错误的常见来源。无论代码是正确的还是错误的,读者都无法仅从那一行来判断程序员的意图。

同样,目的是什么ptr != 0?检查指针是否为 NULL 或指向的数据是否为零,或者数据是否具体是字符串末尾的空终止符?

因此 MISRA 强制执行显式检查。类似于 MISRA 建议的代码if(ptr != NULL)if(*ptr != '\0')这里程序员的意图非常清楚。

你的问题到处都是这个问题!您*p在某些地方和p某些地方打字。const char* p = str;...p != '\0'显然是一个错误,如果那是您的实际代码,那么 MISRA 只是将您从中拯救出来。

因此我将其更改为p != '\0'应该直接转换为空字符。

事实上,这是符合 MISRA 的代码。同样,假设pischar和 not char*

这反过来又给出了 MISRA.LITERAL.UNSIGNED.SUFFIX 违规,即“无符号整数文字 ''\0'' 没有 'U' 后缀”。

那是胡说八道。'\0'是一个字符常量,属于charC++ 类型。您的工具必​​须将其与常规整数常量(十进制、八进制或十六进制)混淆,U如果打算在无符号算术中使用它们,则需要后缀。

现在 MISRA 通常对八进制转义序列皱眉,但在 MISRA-C:2004 中,很多人(真诚地包括你的)向委员会指出,\0必须将其作为一个有效的例外。这已修复并\0在 2007 年 7 月发布的 MISRA-C:2004 TC1 中生效。我不确定该修复是否已进入原始 MISRA-C++:2008,或者是否也有 MISRA-C++ 的 TC。

无论如何,使用'\0'空终止符很好并且符合 MISRA。只要您只使用它来与其他char类型的操作数进行比较。

于 2020-04-02T12:23:53.310 回答