简体   繁体   中英

Why hardware register access is through unsigned datatype

I was going through some examples and unsigned is used in all of them. Is it safe to use int type, if used properly? Like in the example below, 0x12345678 address will have 0xFFFFFFFF written to it irrespective of ptr being defined as signed or unsigned.

volatile unsigned int* ptr = (volatile unsigned int* ) 0x12345678; 

*ptr = 0xFFFFFFFF;

Why is it safe to use unsigned instead of signed for register access?

I think that unsigned C arithmetic is closer to machine registers arithmetic. It is because the C language definition says that, if signed integer arithmetic operation results into a number not fitting the given type (overflow) then the actual result of the operation is undefined. So it can be anything. While in unsigned arithmetic:

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type.

which is the same as happens in machine registers.

Your example is another case, the line:

*ptr = 0xFFFFFFFF;

creates a constant 0xFFFFFFFF of type unsigned long int . The type is unsigned instead of int because the value is bigger than the maximum integer value. If the variable ptr was of type int* , then the compiler would need to convert unsigned to signed before the assignment. This would cause overflow and the result of this assignment would be undefined. Although I do not know a compiler which would generate any arithmetic operation when casting from unsigned to int .

If ptr was defined as int* , and you would want to be correct, then your line should be:

*ptr = -1;

Most hardware registers are either not arithmetic objects (they may be bitfields rather than semantically numeric), or if they do represent a number it is unusual for them to be semantically signed ( a negative value would make no sense for a baud rate divisor for example).

So often, while a signed type may make no difference at the low level, it makes no semantic sense at the high level.

Critically perhaps, the >> operator, often used in processing hardware register values, has implementation defined behaviour for signed types; so to avoid mixed sign operations and the associated implicit conversions introducing errors, you should use unsigned in most cases.

I would suggest that unless the hardware register is semantically signed numeric, then you should use unsigned consistently for not just the registers, but also operands in expressions with register operands.

The answer is simple: the value you use is unsigned (meaning that the literal 0xFFFFFFFF is unsigned). You could assign it to any data type that can hold it - even a float or double could be used. But, you want to store an unsigned value and see it as an unsigned (for example, the %x specifier of printf, that prints a hex value, casts it to unsigned). So, if your data is in the entire process unsigned, why not have the data type of its container unsigned too?

The processor register you write to doesn't know or care how your compiler defines the value, so long as the correct value is written. I upvoted the question because you tried to find an answer before posting.

As stated before, being unsigned or signed is stored the same way in the hardware register. It is the higher level c that interprets this value as either being a signed or unsigned number.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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