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) {}