Types in C

Imagine you want to create a programming language that is capable to fully interoperate with the platform’s C implementation’s ABI for C. I.e., a language that can call any C function on any platform. What types do you need? How do they behave?

Quite a few, it turns out. More than I’d like.

Ftr, Hare is not such a language.

Integer types

C has integer types as follows:

Enumerated types have a few rules on with which integer type of char, the bit-precise integer types, and the signed and unsigned integer types other than bool it is compatible with and with which other enumerated types it is compatible with.

Other than that, only integer types declared by the standard library are compatible with other types of the listed ones. There are few guarantees: size_t is the same type as that resulting from the sizeof operator, which is any standard or extended unsigned integer type; int16_t is incompatible with _BitInt(16), even though their size and range is the same; memory_order is compatible with one of char, the bit-precise integer types, and the signed and unsigned integer types other than bool. intptr_t is not a bit-precise integer type, but could be a standard or extended signed integer type or char or an enumerated type.

If some type is specified to be compatible or even the same as some other specific type, your language need only define one of them. If the C implementation has freedom on which type some type is the same or compatible as, your language ought to provide names for both types. For example, you can get away with saying “instead of char16_t just use the equivalent of int_least16_t,” but you can’t say “instead of ptrdiff_t, just use isize or the like.”

The integer types are represented as two’s complement. An unsigned integer type has padding bits and value bits, a signed integer type has those and a sign bit. Which bits correspond to which bits of a different type is not specified.

unsigned char uc = 1;
_BitInt(CHAR_BIT) bi;
memcpy(&bi, &c, 1);
bool b = true;
char c;
memcpy(&c, &b, 1);
printf("%d\n%d\n", bi, c);
 * Possible output:
 *    4
 *    -512

Floating types

There are a few less floating types than there are integer types. Which is nice, because floating types are more complicated than integer types. There are three standard floating types: float, double, and long double; each a sub-type of the next one.

TODO: talk about Annex F, G, H; complex types; everything

Struct types

Structs have a few rules attached to them:

Union types


Array types

Array types are easy, mostly. There are VLAs, of course. Functions with array parameters or return types won’t be able to be called from C.

Pointer types

Pointers to objects are iterators for arrays. Pointers to functions are the means to call functions. There are a few finer points to pointer types: Pointers have provenance. There is a special type, in C dubbed “pointer to void,” whose only operations are casts to and fro other object pointer types and integer types.

Function types


Atomic types


Qualified types