如何解决由于纯字符签名,哪些工具可以诊断 C++ 可移植性问题?
我们最近发现了一行代码相当于
bool should_escape_control_char(char ch) {
return (ch < 0x20); // control chars are 0x00 through 0x1F
}
如果普通 char
未签名,此方法有效;但是如果普通的 char
被签名,那么这个过滤器也会意外地捕获负字符。 (最终的结果是一个简单的 JSON 编码器将 "é"
编码为 "\u00c3\u00a9"
,因为对于编码器来说,它看起来像一对负字符,然后被单独编码。)
IMO,这里的原罪是我们将普通的 char
表达式与整数进行比较,结果取决于 char
的符号。我希望编译器告诉我们:
fantasy-warning: this comparison's result may depend on the signedness of plain char
return (ch < 0x20); // control chars are 0x00 through 0x1F
^~~~~~~~~
fantasy-note: cast the operand to silence this diagnostic
return (ch < 0x20); // control chars are 0x00 through 0x1F
~~
(signed char)(ch)
我惊讶地发现 Clang 在这种情况下没有提供警告选项;而且我在 GCC 中也没有看到任何警告选项。
- 我是不是找对地方了?
- 在这种情况下,有哪些工具/linter/静态分析器会发出警告?
解决方法
即使您将其更改为,您的代码也无法移植
bool should_escape_control_char(unsigned char ch)
因为您仍在对平台上的字符编码做出假设。使用
int std::iscntrl( int ch );
取而代之,或等效于 C 语言,具体取决于您使用的语言。
参考https://en.cppreference.com/w/cpp/string/byte/iscntrl
(可从该站点访问 C 版本)。
,我使用的静态分析器没有诊断出原始示例。编写单元测试并使用无符号和有符号字符编译它们有助于在自动化测试阶段捕获此类错误。
当使用无符号数时,将它们与显式无符号操作数进行比较比让有符号操作数隐式转换更安全。因此,假设 char 是无符号的:
bool should_escape_control_char(char ch) {
return ch < 0x20u; // control chars are 0x00 through 0x1F
// ^
}
在这种情况下,如果假定的 char 符号是错误的,(至少有一些?)编译器会在 char 被签名并启用警告时发出警告:
warning: comparison of integer expressions of different signedness: 'char' and 'unsigned int' [-Wsign-compare]
与其依赖幻数,不如使用标准库中的 std::iscntrl
:
bool
is_control_c0(unsigned char ch) {
return std::iscntrl(ch
// provide locale if not using currently active
);
}
请注意,接受单个窄字符(即代码单元)的函数无法匹配 UTF-8 中的所有控制代码点,因为 C1 控制代码被编码为两个代码单元。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。