带有签名/无符号整数和函数调用的C / C ++最佳实践

时间:2016-09-26 11:38:47

标签: c++ c

我问这个问题有两种不同的语言:C和C ++。

调用具有相反整数符号期望的函数时,最佳做法是什么?我们的代码需要什么?

例如:

uint32       _depth;                        // uint32 = DWORD
int          depth;

_BitScanForward(&_depth, (uint32)input);    // DWORD, DWORD
depth = (int)_depth;

_BitScanForward期待DWORD(uint32)参数。变量input是int16类型,我需要在我的代码中将结果_depth作为int32处理。

  1. 我是否需要关注如图所示的input投射?我知道编译器会可能为我做,但最佳做法是什么?
  2. _depth声明为int32是否可以接受,因此避免之后必须将其强制转换?
  3. 注意:

    我对编译器的评论是基于经验的。我编写的代码在VS中没有警告编译但在执行时崩溃。原来我正在调用一个incorect width int的函数。所以我不再将这个话题留给编译器了。

    修改

    答案很有帮助,谢谢。让我提炼我的问题。如果没有宽度问题,即函数不期望比传入的更窄的int(obvioulsy将失败),那么依靠编译器处理符号和宽度差异是否可以?

4 个答案:

答案 0 :(得分:37)

我强烈建议将该函数隐藏到自定义包装函数中,该函数与您首选的API一致(并且在此函数中执行适当的显式转换)。在使用特定于编译器的函数的情况下,这具有额外的优点,即通过重新实现该包装函数,将它移植到不同的编译器(你是否想要这样做)会更容易。

答案 1 :(得分:9)

从任何比saveFooData()窄的整数类型转换为宽度相同或宽于int的任何整数类型时,编写显式转换非常重要。如果你不这样做,编译器将首先将值转换为int,因为"整数提升"规则,然后到目标类型。这几乎总是错误的,如果我们今天从头开始,我们就不会以这种方式设计语言,但出于兼容性考虑,我们仍然坚持使用它。

系统提供的typedef(如intuint16_tuint32_tWORD可能比DWORD更窄,更宽或相同;在C ++中,你可以使用模板来解决它,但在C中你不能。因此,您可能希望为涉及这些的任何转换编写显式强制类型转换。

答案 2 :(得分:4)

那有点取决于你的用法等:

如果我可以使用所需类型,我只需使用类型。

如果没有: 在隐式转换可能导致上溢/下溢的数据类型的情况下,编译器应该警告您。所以我通常会有这些警告,并将隐式转换更改为显式转换。

我有两种不同的方法:

如果我100%确定我从未在签名/无符号int之间的边界上/下溢,我使用static_cast。 (通常用于转换不同的API。比如size()返回int vs size_t)。

当我不确定或有可能时,我超出了我使用boost::numeric_cast的界限。当你超越边界时会抛出异常,从而显示何时发生这种情况。

具有例外情况的方法遵循以下操作:如果出现问题而导致硬故障/崩溃/终止,而不是继续使用损坏的数据,然后在其他地方崩溃或使用未定义的数据执行其他操作。

答案 3 :(得分:1)

首先,您的编译器会隐式转换,并会在任何有意义的警告级别上发出警告。

您执行的两个强制转换都是强制转换,编译器(或您的同事)无法轻易确定它们是否正确,因此使用边界测试进行显式转换或显式转换是最佳做法。您选择哪种方法取决于您对数据的了解。最安全的方法是检查边界条件。最简单的方法是简单地转换(在C ++中请使用static_cast而不是C风格的转换)。