Our next step on the libc bringup adventure is an important one: we need to define the standard types. In order to implement the standard types in an extensible manner, we need to support different type definitions on different platforms.
Today we’ll look into the implementation of two headers: stddef.h and stdint.h. Next week we will tackle more platform-specific headers, such as limits.h and endian.h
Table of Contents:
stddef.h
If you look into your system’s stddef.h header, or even Musl libc’s implementation, you will see a large number of types. Any system-wide types are typically thrown into stddef.h to provide convenient global access.
We are going to skip most of those types and focus only on this small set:
size_tssize_tNULLoffsetofmax_align_tptrdiff_t
Feel free to follow Apple and Musl’s lead and add in other system-wide types to your stddef.h implementation.
First we’ll take a look at the implementation specifics for the stddef.h. Following the implementation overview we’ll look at the completed header.
NULL
NULL is a very important definition. In C, it is defined as (void*)0, but for C++ we’ll need to make sure it is only represented as 0:
#ifdef __cplusplus
#define NULL 0L
#else
//not C++
#define NULL ((void *) 0)
#endif
offsetof
offsetof is a very useful macro. If you have a recent C compiler, this instruction is likely a builtin. If not we still provide the macro implementation of the function.
#if __GNUC__ > 3
#define offsetof(type, member) __builtin_offsetof(type, member)
#else
#define offsetof(type, member) ((size_t)( (char *)&(((type *)0)->member) - (char *)0 ))
#endif
max_align_t
max_align_t is a new implementation, requiring C11/C++11.
#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|| (defined(__cplusplus) && __cplusplus >= 201103L)
typedef long double max_align_t;
#endif
ptrdiff_t
ptrdiff_t is one of the types that can have different definitions depending on your target architecture.
For architecture-specific definitions, we will create standalone header files that will be included in our primary stddef.h header. This allows us to switch which architecture headers to include at compile time.
#ifndef __PTRDIFF_T_H_
#define __PTRDIFF_T_H_
typedef long ptrdiff_t;
#endif // __PTRDIFF_T_H_
size_t
size_t and ssize_t are also types that requires a platform-specific definitions. We’ll create another standalone header and implement those types:
#ifndef __SIZE_T_H_
#define __SIZE_T_H_
typedef unsigned long size_t;
typedef long ssize_t;
#endif // __SIZE_T_H_
Completed Header
Now that we’ve looked at each of the individual types, let’s put them all together into a comprehensive header. Don’t forget that you can add other system-wide type definitions in stddef.h.
Note the following lines:
#include <_types/_size_t.h>
#include <_types/_ptrdiff_t.h>
These headers are where we put our definitions for size_t, ssize_t, and ptrdiff_t. The _types folder referenced is included for each architecture that I support.
#ifndef __STDDEF_H_
#define __STDDEF_H_
#include <_types/_size_t.h>
#include <_types/_ptrdiff_t.h>
#pragma mark - NULL -
#ifdef __cplusplus
#define NULL 0L
#else
//not C++
#define NULL ((void *) 0)
#endif
#pragma mark - offsetof -
#if __GNUC__ > 3
#define offsetof(type, member) __builtin_offsetof(type, member)
#else
#define offsetof(type, member) ((size_t)( (char *)&(((type *)0)->member) - (char *)0 ))
#endif
#pragma mark - max_align_t -
#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|| (defined(__cplusplus) && __cplusplus >= 201103L)
typedef long double max_align_t;
#endif
#endif //__STDDEF_H_
stdint.h
stddef.h was a pretty straightforward implementation. stdint.h requires more platform-specific definitions. Let’s take a look at those first.
Platform-Specific Standard Types
Similar to size_t and ptrdiff_t, I define the standard types in the arch-specific _types folder.
For the sake of readability, I have grouped all of my type definitions for x86_64 into one block. Each of these definitions is a different header in my repository. You can use the combined or split version – there’s no hard rule here!
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef long int intmax_t;
typedef long intptr_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef long unsigned int uintmax_t;
typedef unsigned long uintptr_t;
Completed Header
For the main header implementation, I leveraged Apple’s Open Source libc implementation of stdint.h. For brevity, I will not include the full file. Please refer to the Apple implementation, or check my implementation on embedded-resources.
I want to highlight the section below. Note that each of the types is included from the arch-specific location:
/* 7.18.1.1 Exact-width integer types */
#include <_types/_int8_t.h>
#include <_types/_int16_t.h>
#include <_types/_int32_t.h>
#include <_types/_int64_t.h>
#include <_types/_uint8_t.h>
#include <_types/_uint16_t.h>
#include <_types/_uint32_t.h>
#include <_types/_uint64_t.h>
/* 7.18.1.2 Minimum-width integer types */
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
/* 7.18.1.3 Fastest-width integer types */
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
/* 7.18.1.4 Integer types capable of holding object pointers */
#include <_types/_intptr_t.h>
#<span class="hljs-meta-keyword">include <_types/_uintptr_t.h>
<span class="hljs-comment">/* 7.18.1.5 Greatest-width integer types */
<span class="hljs-meta">#<span class="hljs-meta-keyword">include <_types/_intmax_t.h>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include <_types/_uintmax_t.h>
Putting it All Together
Please see embedded-resources for completed stddef.h and stdint.h implementations. I have also included example headers for x86_64.
