4.3.1 Assignment and comparison operators
There are issues that, if a data value is cast from a larger size to a smaller size, the upper bits of the larger values are stripped. In general, this stripping causes a compiler warning, so these are easy issues to catch. However, there are a few cases where compilation is free of errors and warnings on 32-bit platforms but generates errors or warnings on 64-bit platforms. The only way to guarantee catching these errors early on is to compile for both 32-bit and 64-bit processors during the entire development process.
When a warning is generated by a 64-bit processor, it can be eliminated by explicitly casting the larger data type to the smaller data type. However, the developer needs to make sure that this casting is the right solution because the upper bits of the larger data value are stripped.
The example below shows several examples that generate a warning and how to
eliminate it with an explicit cast. The last example is the most interesting
because it does not generate any warnings on a 32-bit architecture, but does on
64-bit. This difference is because a UINTN
on 32-bit CPUs is identical to
UINT32
, but UINTN
on 64-bit CPUs is identical to a UINT64
.
Example 8-Assignment operation warnings
#include <Uefi.h>
UINT8 Value8;
UINT16 Value16;
UINT32 Value32;
UINT64 Value64;
UINTN ValueN;
//
// Warning generated on 32-bit CPU
// Warning generated on 64-bit CPU
//
Value8 = Value16;
//
// Works, upper 8 bits stripped
//
Value8 = (UINT8)Value16;
//
// Works
//
Value16 = Value8;
//
// Warning generated on 32-bit CPU
// Warning generated on 64-bit CPU
//
Value8 = Value32;
//
// Works, upper 24 bits stripped
//
Value8 = (UINT8)Value32;
//
// Works
//
Value32 = Value8;
//
// Warning generated on 32-bit CPU
// Warning generated on 64-bit CPU
//
Value8 = Value64;
//
// Works, upper 56 bits stripped
//
Value8 = (UINT8)Value64;
//
// Works
//
Value64 = Value8;
//
// Warning generated on 32-bit CPU
// Warning generated on 64-bit CPU
//
Value8 = ValueN;
//
// Works
// Upper 24 bits stripped on 32-bit CPU
// Upper 56 bits stripped on 64-bit CPU
//
Value8 = (UINT8)ValueN;
//
// Works
//
ValueN = Value8;
//
// Works on 32-bit CPU
// Warning generated in 64-bit CPU
//
Value32 = ValueN;
//
// Works on 32-bit CPU
// Upper 32-bits stripped on 64-bit CPU
//
Value32 = (UINT32)ValueN;
Example 9, below, is very similar to Example 8 except the assignments have been
replaced with comparison operations. The same issues shown are generated by all
the comparison operators, including >
, <
, >=
, <=
, !=
, and ==
. The
solution is to cast one of the two operands to be the same as the other
operand. The first four cases are the ones that work on 32-bit platforms with
no errors or warnings but generate warnings on 64-bit architectures. The next
four cases resolve the issue by casting the first operand, and the last four
cases resolve the issue by casting the second operand. Care must be taken when
casting the correct operand because a cast from a larger data type to a smaller
data type strips the upper bits of the operand. When a cast is performed to
INTN
or UINTN
, a different number of bits are stripped for 32-bit and
64-bit architectures.
Example 9-Comparison operation warnings
#include <Uefi.h>
UINT64 ValueU64;
UINTN ValueUN;
INT64 Value64;
INTN ValueN;
//
// Works on 32-bit CPU
// Warning generated in 64-bit CPU
//
if (ValueU64 == ValueN) {}
//
// Works on 32-bit CPU
// Warning generated in 64-bit CPU
//
if (ValueUN == Value64) {}
//
// Works on 32-bit CPU
// Warning generated in 64-bit CPU
//
if (Value64 == ValueUN) {}
//
// Works on 32-bit CPU
// Warning generated in 64-bit CPU
//
if (ValueN == ValueU64) {}
//
// Works on 32-bit and 64-bit CPUs
//
if ((INTN)ValueU64 == ValueN) {}
//
// Works on 32-bit and 64-bit CPUs
//
if ((INT64)ValueUN == Value64) {}
//
// Works on 32-bit and 64-bit CPUs
//
if ((UINTN)Value64 == ValueUN) {}
//
// Works on 32-bit and 64-bit CPUs
//
if ((UINT64)ValueN == ValueU64) {}
//
// Works on 32-bit and 64-bit CPUs
//
if (ValueU64 == (UINT64)ValueN) {}
//
// Works on 32-bit and 64-bit CPUs
//
if (ValueUN == (UINTN)Value64) {}
//
// Works on 32-bit and 64-bit CPUs
//
if (Value64 == (INT64)ValueUN) {}
//
// Works on 32-bit and 64-bit CPUs
//
if (ValueN == (INTN)ValueU64) {}