C语言提供用于检查类型有无符号的运算符吗?

6
如果我正在使用一个当前使用特定数字类型别名的库,例如:
typedef uint32_t library_type;

void library_function(library_type x);

如果代码需要传递不同类型的值,我该如何确保即使库更改了typedef,它仍然正确无误?

uint64_t x = get_some_number();

// …need checks here…

library_function((library_type)x);

我可以加入以下检查:

• 检查:

assert(sizeof library_type >= sizeof uint32_t);
assert(x <= UINT32_MAX);

第二次检查将确保我得到的值符合当前library_type的范围。库的作者没有提供LIBRARY_TYPE_MAX定义,因此第一个检查试图在未来编译代码时防止library_type发生更改。
第一个检查可以捕获如果library_type被更改为例如int8_t,但是如果library_type被更改为int32_t呢?它仍然是正确的“大小”,但范围仍然小于我正在检查的范围!
C语言是否提供了一种操作符来内省类型的有符号性,就像sizeof让我知道宽度一样?还有其他方法来确保我对library_type的转换只有在正确的情况下才会被执行吗?

2
你混淆了运行时检查和编译时检查。C语言在运行时并不真正支持动态类型(除非你自己构建一些方案来存储类型,以便重新解释C原本视为原始数据的内容),因此,任何用于确定源代码是否已更改的检查都必须在编译时进行,而不是像assert()那样在运行时进行检查。 - Chris Stratton
看起来C++11提供了std::is_signed; 我在想C语言中是否有类似的东西(以及这是否是正确的方法;-) - natevw
1
你是在试图防止对库源代码的错误编辑,还是在运行时传递给库的错误参数?这两个问题都不是特别可解决的,但在你澄清你确切的担忧之前,这个问题真的无法回答。 - Chris Stratton
3
你能不能不使用显式转换,然后通过 -Wconversion 捕获错误的隐式转换呢?得到类似这样的提示:conversion to uint32_t {aka unsigned int} from int32_t {aka int} may change the sign of the result - kaylum
2
那么在调用函数之前,将其转换为您想要检查的类型。 uint32_t x_cast = (uint32_t) x; library_function(x_cast); - kaylum
显示剩余5条评论
2个回答

7

是的,关系运算符结合类型转换运算符。例如:

_Bool TYPE_is_signed = ((TYPE)-1 < 0);

或者作为断言:

assert((TYPE)-1 < 0); // Require that TYPE is signed
assert((TYPE)-1 > 0); // Require that TYPE is unsigned

1
整洁,如果需要的话可以转换成宏。在实践中,我可能更喜欢@kaylum的解决方案,即使用中间转换为当前底层类型(例如将其强制转换为uint32_t而不是library_type)并让编译器捕获任何破坏性更改。但这个回答了我的问题。 - natevw
1
assert(((TYPE1)-1 < 0) == ((TYPE2)-1 < 0)); - R.. GitHub STOP HELPING ICE

2
我该如何确保需要传递不同类型的值的代码仍然正确,即使库更改其typedef?
您试图防范的情况是一种“不负责任的人类行为”,而不是技术问题。
在API中更改参数的typedef是一种“破坏性变化”——就像任何其他行为变化一样。如果这种变化超出了错误修复,则很可能提示其他更微妙和严重的变化。
破坏性变化应在发布说明中记录。
通常,如果有自动执行API的破坏性变更的强制执行,则是通过版本标识符或能力查询等方式进行检查的,可以在构建和/或运行时检查——库头文件中会有#define LIBRARY_WHATEVER_VERSION 3 ,然后您的代码可以具有预处理器指令来检查。
当破坏性变化真正严重时,通常软件本身会被重新命名,以便错误的版本甚至不能满足#include或链接尝试。

2
我认为你正在被这个假想库的设计所分心,这个库恰好由一个对我们的意见毫不关心的巨大公司控制。我能写可移植的 C 代码来检测一个数字是否可以转换为一个更小但否则未知的类型吗? - natevw
1
我认为你正在被一个破坏性的变化所分心,而忽略了其他变化。你的供应商不会在不升级版本号的情况下随意更改事物。在开始使用新版本之前,请花时间了解这些变化!如果没有编码版本控制,并且你认为同事可能在构建设置方面有些马虎,那么请让你的构建系统检查头文件的md5sum。更好的方法是将所有供应商可交付内容捕获到git子模块中,即使他们只是向你提供头文件+二进制zip文件,你仍然可以跟踪它们的内容并在git中查看有意义的头文件差异。 - Chris Stratton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接