Oli*_*ock 5 c++ unsigned signed
混合有符号和无符号算术的典型示例似乎是:
\n unsigned int u = 10;\n int a = -42;\n auto tmp1 = u - a;\n std::cout << tmp1 << std::endl;\n int tmp2 = tmp1;\n std::cout << tmp2 << std::endl;\nRun Code Online (Sandbox Code Playgroud)\n(请注意,我使用的是auto tmp1这样我可以显示中间结果并检查类型。当然,在实际代码中,这都是一行)
如果你启用足够多的警告(-Wconversion在 clang-13 上,另外,-Wsign-conversion在 gcc-11 上),编译器会很好地抱怨:
main.cpp:148:21: warning: conversion to \xe2\x80\x98unsigned int\xe2\x80\x99 from \xe2\x80\x98int\xe2\x80\x99 may change the sign of the result [-Wsign-conversion]\n 148 | auto tmp1 = u - a;\n | ^\nmain.cpp:150:16: warning: conversion to \xe2\x80\x98int\xe2\x80\x99 from \xe2\x80\x98unsigned int\xe2\x80\x99 may change the sign of the result [-Wsign-conversion]\n 150 | int tmp2 = tmp1;\nRun Code Online (Sandbox Code Playgroud)\n但至少“答案是正确的”:
\noutput
52\n52\nRun Code Online (Sandbox Code Playgroud)\n很好地解释了为什么这仍然“有效”,在这里:\n /sf/answers/1792679801/
\n当然,一般且正确的建议是:“不要混合有符号和无符号类型”。
\n然而,最近,在用户选择类型的通用代码中,我遇到了这个简化的示例:
\nmain.cpp:148:21: warning: conversion to \xe2\x80\x98unsigned int\xe2\x80\x99 from \xe2\x80\x98int\xe2\x80\x99 may change the sign of the result [-Wsign-conversion]\n 148 | auto tmp1 = u - a;\n | ^\nmain.cpp:150:16: warning: conversion to \xe2\x80\x98int\xe2\x80\x99 from \xe2\x80\x98unsigned int\xe2\x80\x99 may change the sign of the result [-Wsign-conversion]\n 150 | int tmp2 = tmp1;\nRun Code Online (Sandbox Code Playgroud)\n如果您启用了正确的警告,编译器仍然会很好地抱怨:
\nmain.cpp:155:17: warning: conversion to \xe2\x80\x98unsigned int\xe2\x80\x99 from \xe2\x80\x98int\xe2\x80\x99 may change the sign of the result [-Wsign-conversion]\n 155 | auto avg1 = sum / count;\n | ^~~\nmain.cpp:157:16: warning: conversion to \xe2\x80\x98int\xe2\x80\x99 from \xe2\x80\x98unsigned int\xe2\x80\x99 may change the sign of the result [-Wsign-conversion]\n 157 | int avg2 = avg1;\nRun Code Online (Sandbox Code Playgroud)\n答案是灾难性的错误:
\noutput
429496719\n429496719\nRun Code Online (Sandbox Code Playgroud)\n在实际代码中,它在一个循环中运行,并avg反馈到sum. 于是sum很快就溢出来了。有符号整数溢出这是未定义的行为。我的UBSan尽职尽责地开始了,蝴蝶从电脑里飞出来给我做午饭。
当用户选择类型时,在通用代码中解决此问题的安全方法是什么?
\nauto avg1 = sum / static_cast<int>(count); ??有效,不再有 UB,正确答案,并且没有警告。但看起来像是一个木棍/大锤,并且可能隐藏其他问题?sum或类似概念) ,使得、count和avg始终具有相同的“符号”。或者完全是别的什么......?
\n编辑
\n为了清楚起见,下面是玩具模板的样子,以及用户可能会如何被抓住。
\n52\n52\nRun Code Online (Sandbox Code Playgroud)\nOutput
-10\n429496719\nRun Code Online (Sandbox Code Playgroud)\n对于那些对较长的激励示例感兴趣的人,此代码审查中已详细说明了所有内容:\n https://codereview.stackexchange.com/questions/274171/generic-exponential-damping-to-smooth-noisy-signals
\n| 归档时间: |
|
| 查看次数: |
380 次 |
| 最近记录: |