如何在C中正确将负值转换为无符号类型?

huangapple go评论48阅读模式
英文:

How to properly do negative value cast to an unsigned type in C?

问题

I want to store a register value and do the bitwise NOT operator like below

typedef union TEST_REG {
  uint32_t                         u32Register;
  uint8_t                          Byte[4];
  uint16_t                         hword[2];
} tst_reg;

#define TEST_REGISTER              ((volatile tst_reg*) 0x7023100CUL) // Register

Below is a sample code to store the value

#define CHECK_FLAG                  (0x00000004)
TEST_REGISTER->u32Register &= (uint32_t)(~(CHECK_FLAG));

But when I perform the TEST_REGISTER->u32Register &= (uint32_t)(~(CHECK_FLAG)); code, QAC is throwing a warning like

Constant: Negative value cast to an unsigned type

I understood that if we do a NOT (~) operator the Hexa values will change to negative number.

So I would like to know how to properly do the negative value cast to an unsigned type ? Any suggestions ?

英文:

I want to store a register value and do the bitwise NOT operator like below

typedef union TEST_REG {
  uint32_t                         u32Register;
  uint8_t                          Byte[4];
  uint16_t                         hword[2];
} tst_reg;

#define TEST_REGISTER              ((volatile tst_reg*) 0x7023100CUL) // Register

Below is a sample code to store the value

#define CHECK_FLAG 					(0x00000004)
TEST_REGISTER->u32Register &= (uint32_t)(~(CHECK_FLAG));

But when I perform the TEST_REGISTER->u32Register &= (uint32_t)(~(CHECK_FLAG)); code, QAC is throwing a warning like

Constant: Negative value cast to an unsigned type

I understood that if we do a NOT (~) operator the Hexa values will change to negative number.

So I would like to know how to properly do the negative value cast to an unsigned type ? Any suggestions ?

答案1

得分: 5

> 但当我执行TEST_REGISTER->u32Register &= (uint32)(~(CHECK_FLAG));代码时,QAC会发出警告,如下所示
>
> Constant: Negative value cast to an unsigned type

首先,C语言不会对将负整数值转换为无符号类型表示异议。这种行为是明确定义的。问题出在MISRA上。事实上,MISRA基本上反对将~应用于带符号整数类型的表达式,而且反对将带符号整数类型的复合表达式转换为不同的“必要类型类别”,如无符号整数。我不确定QAC的具体原因,但MISRA不关心要转换的表达式的值是否实际上为负数。

解决方法是从一开始就使用无符号整数。您可以通过在常量后面加上uU来实现这一点:0x00000004u。此外,stdint.h包含用于编写具有显式宽度类型的常量的宏,通过使用适当的宏,您可以解决符号问题,并避免强制转换:

#define CHECK_FLAG                  (UINT32_C(0x00000004))
TEST_REGISTER->u32Register &= ~CHECK_FLAG;
英文:

> But when I perform the TEST_REGISTER->u32Register &=
> (uint32)(~(CHECK_FLAG));
code, QAC is throwing a warning like
>
> Constant: Negative value cast to an unsigned type

In the first place, C has no objection to converting negative integer values to unsigned types. The behavior is well-defined. It is MISRA that objects. In fact, MISRA fundamentally objects to applying the ~ to an expression of signed integer type, and it objects to converting a composite expression of signed integer type to a different "essential type category", such as unsigned integer. I'm not sure exactly where QAC is coming from, but MISRA doesn't care whether the value of the expression being converted is actually negative.

The thing to do is to start with an unsigned integer in the first place. You can do that by suffixing your constant with u or U: 0x00000004u. Alternatively, stdint.h contains macros for writing constants of explicit-width types, and by using the appropriate one of those, you can solve the signedness issue and avoid a cast:

#define CHECK_FLAG                  (UINT32_C(0x00000004))
TEST_REGISTER->u32Register &= ~CHECK_FLAG;

答案2

得分: 1

在使用~运算符之前进行类型转换,或者将CHECK_FLAG定义为带有强制转换或在字面量中添加'u'来指定它是无符号字面量的uint32类型。

~((uint32)CHECK_FLAG)

或者

#define CHECK_FLAG ((uint32)0x00000004)
#define CHECK_FLAG (0x00000004u)

请参考此页面:http://port70.net/~nsz/c/c11/n1570.html#6.4.4.1 以了解C语言中不同后缀的含义。

没有后缀的字面量始终被解释为int。因此,让我们看看当你写下以下代码时会发生什么:

(uint32)(~(CHECK_FLAG))

CHECK_FLAG是字面量4,在反转位时被解释为带符号的int,因此变为负值。

(uint32)(-5)

现在你将一个负值强制转换为无符号类型,编译器会警告你。

如果在反转位之前将其转换为uint32类型(或者一开始就使用无符号字面量),那么反转操作不会得到负值,因为在反转位时变量已经是无符号的了,无符号值不会变成负数。

英文:

Cast before using the ~ operator, or define CHECK_FLAG as a uint32 with a cast or by adding 'u' to the literal to specify it is an unsigned literal.

~((uint32)CHECK_FLAG)

or

#define CHECK_FLAG ((uint32)0x00000004)
#define CHECK_FLAG (0x00000004u)

See this page: http://port70.net/~nsz/c/c11/n1570.html#6.4.4.1 for the different suffixes in C.

A literal without a suffix is always interpreted as an int. So let's take a look at what happens when you write:

(uint32)(~(CHECK_FLAG))

CHECK_FLAG, which is the literal 4 and therefore behaves as a signed int when inverting the bits, becomes a negative value as a result of the bit inversion.

(uint32)(-5)

Now you're casting a negative value to an unsigned type, which the compiler warns you about.

If you cast to uint32 to before you invert (or use an unsigned literal to begin with), then the inversion does not result in a negative value because the variable is already unsigned when you are inverting the bits, and unsigned values cannot become negative.

答案3

得分: 1

使用掩码时,最好使用无符号常数(这样就没有负值了)。()不是必需的,但也不会有害。

通常,强制转换表示弱代码。

// #define CHECK_FLAG                  (0x00000004)
#define CHECK_FLAG                  0x00000004U
// TEST_REGISTER->u32Register &= (uint32)(~(CHECK_FLAG));
TEST_REGISTER->u32Register &= ~CHECK_FLAG;
英文:

> How to properly do negative value ...

With masking, best to use unsigned constants (there are no negative values then). The () are not needed, but not harmful either.

Typically a cast indicates weak code.

// #define CHECK_FLAG                  (0x00000004)
#define CHECK_FLAG                  0x00000004U
// TEST_REGISTER->u32Register &= (uint32)(~(CHECK_FLAG));
TEST_REGISTER->u32Register &= ~CHECK_FLAG;

答案4

得分: 1

Your MISRA checker should already give a warning at #define CHECK_FLAG (0x00000004). This needs to have a U/u suffix to be MISRA compliant and that's the actual problem here.

Some other things of note:

  • The parenthesis around an integer constant fills no purpose (but could be problematic in case of using this one together with other macros.)

  • Adding a bunch of 0000.... in front of a hex number fills no purpose but to confuse the programmer. C is kind of broken/cheeky when it comes to hex integer constants. Assuming 32 bit system then 0x00000004 is of type int, 0x4 is of type int, but 0x80000000 is of type unsigned int and 0x100000000 is of type long or long long.

    Very easy to write subtle bugs because of this. As some RL anecdote I once took over a broken project for an 8-bitter with 16 bit int where they had made a habit of typing out zeroes just like this, fooling themselves thinking they were getting 32 bit numbers. While in fact the project actually contained a mix of 16 bit int, 16 bit unsigned int and 32 bit long and this was one of the main reasons why the entire program was broken.

Therefore the correct code should be:

#define CHECK_FLAG 0x4u
...
TEST_REGISTER->u32Register &= ~CHECK_FLAG;

The parenthesis spam makes no difference for MISRA compliance in this case - it's just bloat so I removed it. The cast is no longer necessary either since all operands of the expression are unsigned, "essentially unsigned" as MISRA calls it, and then no casts are required.

英文:

Your MISRA checker should already give a warning at #define CHECK_FLAG (0x00000004). This needs to have a U/u suffix to be MISRA compliant and that's the actual problem here.

Some other things of note:

  • The parenthesis around an integer constant fills no purpose (but could be problematic in case of using this one together with other macros.)

  • Adding a bunch of 0000.... in front of a hex number fills no purpose but to confuse the programmer. C is kind of broken/cheeky when it comes to hex integer constants. Assuming 32 bit system then 0x00000004 is of type int, 0x4 is of type int, but 0x80000000 is of type unsigned int and 0x100000000 is of type long or long long.

    Very easy to write subtle bugs because of this. As some RL anecdote I once took over a broken project for an 8-bitter with 16 bit int where they had made a habit of typing out zeroes just like this, fooling themselves thinking they were getting 32 bit numbers. While in fact the project actually contained a mix of 16 bit int, 16 bit unsigned int and 32 bit long and this was one of the main reasons why the entire program was broken.

Therefore the correct code should be:

#define CHECK_FLAG 0x4u
...
TEST_REGISTER->u32Register &= ~CHECK_FLAG;

The parenthesis spam makes no difference for MISRA compliance in this case - it's just bloat so I removed it. The cast is no longer necessary either since all operands of the expression are unsigned, "essentially unsigned" as MISRA calls it, and then no casts are required.

huangapple
  • 本文由 发表于 2023年4月19日 22:22:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76055641.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定