2

I've realized and read that multiplying a uint16_t with another uint16_t results in an integer (it actually seems to be a signed integer? see: ). Given that, do I have to assume that the following function f produces undefined behavior, because there'll be a signed integer overflow?

The overflow would occur, because x*x for x=45000 results in "almost" INT32_MAX and it will then overflow if it is multiplied again by x.

(btw: on my platform int is a int32_t)

#include <stdio.h>
#include <stdint.h>

uint16_t f(uint16_t x) {
    printf("%zu\n", sizeof(x));     // <-- 2
    printf("%zu\n", sizeof(x * x)); // <-- 4
    return x * x * x;
}

int main()
{
    uint16_t x = 45000;
    uint16_t y = f(x);
}

The overflow would occur, because x*x for x=45000 results in "almost" INT32_MAX and it will then overflow if it is multiplied again by x.

Is this correct, or do I make some wrong assumptions?

ikegami
  • 367,544
  • 15
  • 269
  • 518
Kevin Meier
  • 2,339
  • 3
  • 25
  • 52
  • 3
    Unrelated, but note that the `sizeof` operator returns a value of type `size_t`. The correct `printf` format specifier for `size_t` is `%zu`. Mismatching format-specifier and argument type leads to UB. – Some programmer dude Sep 04 '22 at 14:43
  • What, in your own words, do you think `sizeof( x * x )` does? – DevSolar Sep 04 '22 at 14:44
  • Also note that in almost all cases, `sizeof` is a compile-time operation. The expression used for the `sizeof` operator is not evaluated at run-time. – Some programmer dude Sep 04 '22 at 14:44
  • More related to your question: Because of [usual arithmetic conversion](https://en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions) the compiler will perform [integer promotion](https://en.cppreference.com/w/c/language/conversion#Integer_promotions) so `x * x` will be performed as `int` values with an `int` result. That `int` result may then be [converted](https://en.cppreference.com/w/c/language/conversion#Integer_conversions) to a smaller type. – Some programmer dude Sep 04 '22 at 14:48
  • Should "_See:_" be followed by a link or citation? – Clifford Sep 04 '22 at 21:41

2 Answers2

5

do I have to assume that the following function f produces undefined behavior, because there'll be a signed integer overflow?

Yes, on 32-bit int/unsigned implementations. No signed integer overflow on 16-bit int/unsigned ones.

The overflow would occur, because x*x for x=45000 results in "almost" INT32_MAX and it will then overflow if it is multiplied again by x.

Yes and int overflow is undefined behavior (UB).

To avoid int overflow UB, use unsigned math and let the compiler emit efficient code. Works well for int/unsigned as 16, 32, ... bit widths.

// return x * x * x;
return 1u * x * x * x;  // Coerce into using unsigned math
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
3

You are correct that your posted code will invoke undefined behavior due to signed integer overflow.

According to §6.3.1.1 ¶2 of the ISO C11 standard, the uint16_t operands will both get promoted to an int, because an int is 32-bits wide on your platform and therefore able to represent all values representable by uint16_t. If this were not the case, then the operands would get promoted to unsigned int.

Therefore, on platforms on which int is 32 bits wide, you will be getting a signed integer overflow (which is undefined behavior), whereas on platforms on which int is 16 bits wide, you will be getting an unsigned integer overflow (which is not undefined behavior).

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39