5.6 Declarations and Types
5.6.1 Common Data Types
5.6.1.1 The UEFI Specification defines a set of common data types that must be used to ensure portability between different compilers and processor architectures.
Any abstract type that is defined must be constructed from other abstract types or from common EFI data types.
5.6.1.2 The use of int, unsigned, char, void, static, long is a violation of the coding convention.
The corresponding EFI types must be used instead.
"EFI Data Types" below contains the common data types that are referenced in the interface definitions defined by this specification. Per the UEFI Specification, version 2.3.1:
"Unless otherwise specified, all data types are naturally aligned. Structures are aligned on boundaries equal to the largest internal datum of the structure, and internal data is implicitly padded to achieve natural alignment."
Table 6 EFI Data Types (slightly modified from UEFI 2.3.1)
Mnemonic | Description |
---|---|
BOOLEAN |
Logical Boolean. 1-byte value containing a 0 for False or a 1 for True . Other values are undefined. |
INTN |
Signed value of native width. (4 bytes on IA-32, 8 bytes on X64, and 8 bytes on the Intel(R) Itanium(R) processor family) |
UINTN |
Unsigned value of native width. (4 bytes on IA-32, 8 bytes on X64, and 8 bytes on the Intel(R) Itanium(R) processor family) |
INT8 |
1-byte signed value. |
UINT8 |
1-byte unsigned value. |
INT16 |
2-byte signed value. |
UINT16 |
2-byte unsigned value. |
INT32 |
4-byte signed value. |
UINT32 |
4-byte unsigned value. |
INT64 |
8-byte signed value. |
UINT64 |
8-byte unsigned value. |
CHAR8 |
1-byte character. |
CHAR16 |
2-byte character. Unless otherwise specified, all strings are stored in the UTF-16, 2-byte, encoding format as defined by the Unicode 2.1 and ISO/IEC 10646 standards. |
VOID |
Undeclared type. |
EFI_GUID |
128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64bit boundary. |
EFI_STATUS |
Status code. Type UINTN . |
EFI_HANDLE |
Handle to a device driver. Type VOID * . |
EFI_EVENT |
Handle to an event structure. Type VOID * . |
EFI_LBA |
Logical block address. Type UINT64 . |
EFI_TPL |
Task priority level. Type UINTN . |
"Modifiers for Common EFI Data Types" defines modifiers that are used in
function and data declarations. The IN
, OUT
, OPTIONAL
, and UNALIGNED
modifiers are used only to qualify arguments to a function. They should never
appear in a data type declaration. The EFIAPI
modifier is used to ensure the
correct calling convention is used between different modules that are not linked
together. Use this modifier at the entry of drivers, events, and member
functions of protocols.
The EFIAPI
modifier must be used for all UEFI defined API functions, as well
as for any function that takes a variable number of arguments. All protocol
functions as well as public functions exposed by drivers must also be declared
EFIAPI
. This establishes a common calling convention for functions that could
be referenced by other code that has potentially been built using a different
compiler, with a different native calling convention.
Table 7 Modifiers for Common EFI Data Types (reference the UEFI Specification and Beyond Bios)
Mnemonic | Description |
---|---|
IN |
Datum is passed to the function. |
OUT |
Datum is returned from the function. |
OPTIONAL |
Datum that is passed to the function is optional, and a NULL may be passed if the value is not supplied. |
UNALIGNED |
Datum is byte packed and is not naturally aligned. |
VOLATILE |
Declares a variable to be volatile and thus exempt from optimization to remove redundant or unneeded accesses. Any variable that represents a hardware device should be declared as VOLATILE . |
CONST |
Declares a variable to be of type const . This type is a hint to the compiler to enable optimization and stronger type checking at compile time. |
EFIAPI |
Defines the calling convention for EFI interfaces. All EFI intrinsic services and any member function of a protocol must use this modifier on the function definition. |
5.6.2 Constants
5.6.2.1 EFI Constants
"EFI Constants" below lists the EFI constants that should be used to represent certain concepts.
Table 8 EFI Constants
Mnemonic | Description |
---|---|
TRUE |
One = ( 1 < 2 ) == 1; Any non-zero value is TRUE . |
FALSE |
Zero = ( 2 < 1 ) == 0 |
NULL |
VOID pointer to zero. ((void*)0) |
5.6.2.2 Enumerated Types
The elements of the enumerated type must follow the data and function naming convention.
The
enum
shall be declared as atypedef
with the name of thetypedef
following the type and macro naming conventions in` "Type and Macro Names".The last element of the enum should be a maximum member element.
This convention allows for bounds checking on an
enum
to support debugging and sanity checking the value that is assigned to anenum
. It is also recommended that theenum
members be named carefully, such that their names would not tend to collide with other variable or function names.typedef enum { EnumMemberOne, ///< Automatically initialized to zero. EnumMemberTwo, ///< This has the value 1 EnumMemberMax ///< The value 2 here indicates there are two elements. } ENUMERATED_TYPE;
This obviously will not work if values are explicitly assigned out-of-sequence or are duplicated.
All constants that will be used "as is" should be declared as enums.
An enum does not cause code to be generated until the enum is used, whereas a const int will cause space for the int to be allocated as well as the code generated whenever the int is used. The use of enums allows type checking to be performed, while the use of macros does not
.
5.6.2.3 Macro Constants
Constants that will be used to construct other values should be declared as macros. These include bit field definitions and masks.
5.6.2.4 Pointers and Constants
There are three different ways pointers and constants can interact:
Pointer to Constant:
CONST UINTN * PointerToConst;
PointerToConst
is a variable pointer to a constantUINTN
.Constant pointer to variable:
UINTN * CONST ConstPointer;
ConstPointer
is a constant pointer to a variableUINTN
.Constant pointer to constant:
CONST UINTN * CONST ConstPointerToConst;
ConstPointerToConst
is a constant pointer to a constantUINTN
.
5.6.3 Structure Declaration
Structures shall be declared as a typedef
with one of two different styles
depending on the use of the structure. If the structure is not
self-referential, or there is no forward reference to it, the structure may be
defined anonymously; see Section "Structure Reference".
This anonymous definition is valid because we typedef the structure in the definition.
The structure name and typedef name shall follow the type and macro naming conventions in "Type and Macro Names" on page 24`
Structure instances: Variables, parameters, members, etc., must follow the file, function, and data naming conventions in "Identifiers" through "Name Space Rules".
Structures are always defined in a
typedef struct name {...} type;
format.
The "name" tag is allowed only if the structure is self-referential or the target of a forward reference.
5.6.3.1 Structures shall not be directly declared.
The following are not allowed:
struct name {...}; // OK if object of forward reference
struct {...} variable; // Never OK
struct name {...} variable; // Never OK
5.6.3.2 Structure Declaration with Forward Reference or Self-Reference
/// Sample forward declaration of a structure.
typedef struct EFI_STRUCT_NAME EFI_STRUCT_NAME;
/// Sample self-referential structure declaration.
typedef struct EFI_STRUCTURE_NAME {
...
struct EFI_STRUCTURE_NAME *StructPointer; ///< Sample self reference
} EFI_STRUCT_NAME;
5.6.3.3 Structure Declaration without Forward Reference
/** Brief description of sample structure declaration.
*
* Detailed description of purpose and use of this structure.
**/
typedef struct {
Atype memberOne; ///< Briefly describe memberOne
...
Ztype memberN; ///< Briefly describe memberN
} EFI_STRUCTURE_NAME;
5.6.3.4 Bit Fields
A member of a structure or union may be declared to consist of a specified number of bits (including a sign bit, if any). That member is referred to as a bit-field. Bit fields differ from other members in that:
Bit fields may only be of type
INT32
,signed INT32
,UINT32
, or a typedef name defined as one of the threeINT32
variants.It is compiler defined whether
INT32
is signed or unsigned.The order of allocation of bit-fields within a storage unit is compiler defined.
The alignment of the addressable storage unit is unspecified.
A bit-field may not extend from one storage unit into another.
A bit-field with only a colon and a width (no declarator), indicates an unnamed bit-field. Unnamed bit-fields are useful for padding to conform to externally imposed layouts.
Specifying a bit-field with a width of 0 (zero) indicates that no further bit-fields are to be packed into the unit in which the previous bit-field, if any, was placed.
5.6.3.4.1 Visual C++ Specific
The alignment requirement for each non-bit-field member is the same as the largest alignment requirement of the members. Thus, every member will have the same alignment.
A "plain"
int
bit-field is treated as asigned int
bit field.Bit fields are allocated within a storage unit from least-significant to most-significant bit.
5.6.3.4.2 GCC Specific
The alignment requirement for non-bit-field members of structures is determined by the target ABI.
By default, a "plain"
int
bit-field is treated as asigned int
, but this may be changed by the '-funsigned-bitfields' option.The order of allocation of bit-fields within a unit is determined by the target ABI.