Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integer promotion in C operation

Tags:

c

integer

math

uint64_t impulses = 4000000;
uint16_t impulses_per_meter = 999;
uint32_t meters = impulses / impulses_per_meter;

As I understand the impulses_per_meter gets an integer promotion before calculating the final value of the operation impulses / impulses_per_meter, then the result gets truncated to uint16_t.

Is my understanding correct or the result might be incorrect?

By the way, the MCU I'm running this on is 8 bit.

like image 256
Binar Web Avatar asked Jun 28 '26 19:06

Binar Web


2 Answers

There is a part of the standard called "usual arithmetic conversions". Its aim is to determine a common type when the operands of arithmetic operations differ in type and signedness.

When both operands are integers (as is your case), they both undergo integer promotion. After promotion, if both operands are the same type (int), then that is the type of the expression. If they are different but have the same signedness, the standard says:

If the types have the same signedness (both signed or both unsigned), the operand whose type has the lesser conversion rank is implicitly converted to the other type.

In your case, this would mean that impulses_per_meter is implicitly converted to unsigned long long (assuming a data model where uint64_t is the same as unsigned long long).

However, assigning that expression result (uint64_t) to meters (uint32_t) involves truncation and data loss. A modern compiler should issue a warning and you should change your code.

like image 55
Blagovest Buyukliev Avatar answered Jul 01 '26 14:07

Blagovest Buyukliev


In the expression impulses / impulses_per_meter:

  • Normally, implicit integer promotion is carried out on both operands of / (and most other such binary operators) as the first step of "the usual arithmetic conversions".
  • On an 8 bit system, int is 16 bit. impulses_per_meter is already of a type uint16_t with equal conversion rank as int, so no integer promotion is required. impulses is of type uint64_t so no promotion there either.
  • The next step of "the usual arithmetic conversions" is to convert impulses_per_meter to the same type as the operand of / with the greatest conversion rank, in this case to uint64_t.
  • The division is carried out on uint64_t types and the result is of type uint64_t.
  • During assignment to uint32_t, the result of the division gets converted from uint64_t to uint32_t. If the result can't fit in one, you will lose data.

For details check out Implicit type promotion rules.

As a side note, using 64 bit arithmetic on a 8 bit MCU is a horrible idea. 64 bit division in particular is spectacularly inefficient. 4000000 fits inside a uint32_t so I'm not sure what you are even doing here.

like image 36
Lundin Avatar answered Jul 01 '26 14:07

Lundin