简体   繁体   English

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

[英]C / C++ best practices with signed / unsigned ints and function calls

I am asking this question for two different languages: C and C++. 我问这个问题有两种不同的语言:C和C ++。

What is best practice when calling functions that have an opposite integer sign expectation to what we require in our code? 调用具有相反整数符号期望的函数时,最佳做法是什么?

For example: 例如:

uint32       _depth;                        // uint32 = DWORD
int          depth;

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

_BitScanForward is expecting DWORD (uint32) parameters. _BitScanForward期待DWORD(uint32)参数。 The variable input is of int16 type and I need to process the result _depth as an int32 in my code. 变量input是int16类型,我需要在我的代码中将结果_depth作为int32处理。

  1. Do I need to care about casting input as shown? 如图所示,我是否需要关注投射input I know the complier will probably do it for me, but what is best practice? 我知道编译器可能会为我做,但最佳做法是什么?
  2. Is it acceptable to declare _depth as int32 and therefore avoid having to cast it afterwards as shown? _depth声明为int32是否可以接受,因此避免必须如后所示_depth转换它?

NOTE: 注意:

My comment about the complier is based on experience. 我对编译器的评论是基于经验的。 I wrote code that compiled with no warnings in VS but crashed on execution. 我编写的代码在VS中没有警告编译但在执行时崩溃。 Turned out I was calling a function with an incorect width int. 原来我正在调用一个incorect width int的函数。 So I don't leave this topic up to the compiler any more. 所以我不再把这个话题留给编译器了。

EDIT: 编辑:

The answers are helpful, thanks. 答案很有帮助,谢谢。 Let me refine my question. 让我提炼我的问题。 If there are no width issues, ie the function is not expecting a narrower int than what is being passed in (obvioulsy will fail), then is it okay to rely on the compiler to handle sign and width differences? 如果没有宽度问题,即函数不期望比传入的更窄的int(obvioulsy将失败),那么依靠编译器处理符号和宽度差异是否可以?

I would strongly recommend to hide that function into a custom wrapper function which agrees with your preferred API (and within this function do proper explicit casting). 我强烈建议将该函数隐藏到自定义包装函数中,该函数与您首选的API一致(并且在此函数中进行适当的显式转换)。 In the case of using compiler-specific functions this has the additional advantage that it will be much easier to port it to different compilers (should you ever want to do that), by just re-implementing that wrapper function. 在使用特定于编译器的函数的情况下,这具有额外的优点,即通过重新实现该包装函数,将它移植到不同的编译器(如果您想要这样做)将更容易。

It is very important to write an explicit cast when going from any integer type that is narrower than int to any integer type that is the same width or wider than int . 从比int更窄的任何整数类型转换为宽度相同或宽于int任何整数类型时,编写显式转换非常重要。 If you don't do this, the compiler will first convert the value to int , because of the "integer promotion" rules, and then to the destination type. 如果不这样做,编译器将首先将值转换为int ,因为“整数提升”规则,然后到目标类型。 This is almost always wrong, and we wouldn't design the language this way if we were starting from scratch today, but we're stuck with it for compatibility's sake. 这几乎总是错误的,如果我们今天从头开始,我们不会这样设计语言,但为了兼容性,我们坚持使用它。

System-provided typedefs like uint16_t , uint32_t , WORD , and DWORD might be narrower, wider, or the same size as int ; 系统提供的类型定义如uint16_tuint32_tWORDDWORD可能比int更窄,更宽或相同; in C++ you can use templates to figure it out, but in C you can't. 在C ++中,你可以使用模板来解决它,但在C中你不能。 Therefore, you may want to write explicit casts for any conversion involving these. 因此,您可能希望为涉及这些的任何转换编写显式强制类型转换。

Well It kind of depends on your usage etc: 那有点取决于你的用法等:

If I can use the type which is needed I just use the type. 如果我可以使用所需的类型我只使用类型。

If not: Your compiler should warn you in the cases where you implicitly convert datatypes which may result in over/underflows. 如果不是:您的编译器应该在您隐式转换可能导致上溢/下溢的数据类型的情况下发出警告。 So I have those warnings on usually and change the implicit conversion to explicit ones. 所以我通常会有这些警告,并将隐式转换更改为显式转换。

There I have 2 different approaches: 我有两种不同的方法:

If I am like 100% sure that I never over/underflow the boundaries between signed/unsigned int I use static_cast . 如果我100%确定我永远不会在signed / unsigned int之间的边界上/下溢,我使用static_cast (usually for conversion of different APIs. Like size() returning int vs size_t). (通常用于转换不同的API。像size()返回int vs size_t)。

When I am not sure or it may be possible I am beyond the boundaries I use boost::numeric_cast . 当我不确定或有可能我超出界限时我使用boost::numeric_cast This throws an exception when you cast beyond boundaries and thus shows when this happens. 当你超越边界时会抛出异常,从而显示何时发生这种情况。

The approach with the exceptions adheres to the practice to fail hard/crash/terminate if something goes wrong instead of continuing with corrupt data and then crash somewhere else or do other things with undefined data. 如果出现问题而不是继续使用损坏的数据然后在其他地方崩溃或使用未定义的数据执行其他操作,那么具有例外的方法会坚持执行以使其失败或崩溃/终止。

First your compiler will make the casts implicit and will give you a warning on any meaningful warning level. 首先,您的编译器将隐式进行强制转换,并在任何有意义的警告级别上给出警告。

Both casts you perform are casts where the compiler (or your coworkers) cannot easily decide if they are correct, therefor an explicit casting or explicit conversion with a boundary test is best practice. 您执行的两个强制转换都是强制转换,编译器(或您的同事)无法轻易确定它们是否正确,因此使用边界测试进行显式转换或显式转换是最佳做法。 Which you choose depends on your knowledge of the data. 您选择哪种方法取决于您对数据的了解。 The safest way is to check boundary conditions. 最安全的方法是检查边界条件。 The cheapest way is to simply cast (in C++ please use static_cast not C-style casts). 最简单的方法是简单地转换(在C ++中请使用static_cast而不是C风格的转换)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM