Code Snippet 1 (shown below) produces the following -Wconversion warning:
debug_Wconversion.c:10:57: warning: conversion to ‘uint16_t’ from ‘int’ may alter its value [-Wconversion]
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
^
Code snippets 2 and 3 do not produce a -Wconversion warning.
Code Snippet 1:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
Code Snippet 2:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
uint16_t leftOrOperand;
uint16_t rightOrOperand;
leftOrOperand = ((uint16_t) (((uint16_t) byte1) & 0x0050));
rightOrOperand = ((uint16_t) byte2);
result = leftOrOperand | rightOrOperand;
Code Snippet 3:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = (uint16_t) (((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2));
Why does the first code snippet produce the warning, but the others do not? What specifically is causing the warning?
I find this perplexing. The warning in the first snippet insinuates that integer promotion is occurring in the Bitwise Or operation, despite the explicit casting of the operands. The second snippet demonstrates that the Bitwise Or operation does not inherently cause integer promotion. The third snippet performs the same operation as the first snippet if order of operations is preserved, but casts the result of the Bitwise Or before assignment of the result variable. There is clearly something that I fail to understand about the interplay between casting and the Bitwise Or operation. Any help with clarifying my comprehension would be greatly appreciated!
Other potentially relevant information:
Thanks in advance!
Both the bitwise OR operator |
and the bitwise AND operator &
perform integer promotions on both operands. The fact that one of the operands is the result of a cast doesn't change this.
The -Wconversion
flag tends to be a bit overenthusiastic regarding what it warns on. Given a 32-bit int
, a conversion from uint16_t
to int
will not change its value.
The C standard does specify that the minimum range of an int
is -32767 to 32767, so an implementation with this limit could potentially see a value change, though you'll be hard-pressed to find a system the runs gcc where this is the case.
This particular warning is silenced however by a cast. From the man page:
-Wconversion
Warn for implicit conversions that may alter a value. This includes conversions between real and integer, like "abs (x)" when "x" is "double"; conversions between signed and unsigned, like "unsigned ui = -1"; and conversions to smaller types, like "sqrtf (M_PI)". Do not warn for explicit casts like "abs ((int) x)" and "ui = (unsigned) -1", or if the value is not changed by the conversion like in "abs (2.0)". Warnings about conversions between signed and unsigned integers can be disabled by using -Wno-sign-conversion.
For C++, also warn for confusing overload resolution for user-defined conversions; and conversions that never use a type conversion operator: conversions to "void", the same type, a base class or a reference to them. Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless -Wsign-conversion is explicitly enabled.