Mastering GNU C Extensions: typeof, Zero‑Length Arrays, Case Ranges and More in the Linux Kernel
This article explains key GNU C extensions used throughout the Linux kernel—including typeof, zero‑length (flexible) arrays, case range labels, designated initializers, variadic macros, function and variable attributes, built‑in functions, asmlinkage and UL suffixes—showing why they exist and how to apply them safely with concrete code examples.
Linux kernel development relies heavily on GNU C extensions that go beyond standard ANSI C. The following sections introduce each extension, explain its purpose, and provide practical code snippets.
typeof
GNU C adds the typeof operator, which yields the type of an expression. It enables type‑safe macros, for example a max macro that works correctly with side‑effects:
#define max(a,b) ({
typeof(a) _a = (a);
typeof(b) _b = (b);
(void)(&_a == &_b); // warn if types differ
_a > _b ? _a : _b;
})Using typeof ensures the macro evaluates each argument once and preserves the original types.
Zero‑length (flexible) arrays
Also called flexible arrays, a zero‑length array placed as the last member of a struct allows the struct to have a variable size determined at allocation time.
struct line {
int length;
char contents[0];
};
struct line *thisline = malloc(sizeof(struct line) + this_length);
thisline->length = this_length;The size of struct line is only sizeof(int); the actual data follows the struct in the allocated buffer.
Case range labels
GNU C permits a range of values in a case label, written as low ... high. This is useful for compactly handling character ranges or numeric intervals.
switch (*name) {
case '0' ... '9':
val = 10 * val + (*name - '0');
break;
default:
return val;
}Designated (labeled) initializers
Structure members can be initialized out of order by naming them explicitly, which keeps code robust when the struct definition changes.
static const struct file_operations zero_fops = {
.llseek = zero_lseek,
.read = new_sync_read,
.write = write_zero,
.read_iter = read_iter_zero,
.aio_write = aio_write_zero,
.mmap = mmap_zero,
};Variadic macros
Macros can accept a variable number of arguments using ... and __VA_ARGS__. Example from the kernel:
#define pr_debug(fmt, ...) \
dynamic_pr_debug(fmt, ##__VA_ARGS__)Function attributes
GNU C allows attaching attributes to functions, variables, or types to guide compiler optimizations and checks. Common attributes include noreturn, format, const, aligned, etc.
#define __pure __attribute__((pure))
#define __aligned(x) __attribute__((aligned(x)))
#define __printf(a,b) __attribute__((format(printf,a,b)))
#define noinline __attribute__((noinline))Example of a function with the format attribute:
int libcfs_debug_msg(struct libcfs_debug_msg_data *msgdata,
const char *format1, ...) __attribute__((format(printf,2,3)));Variable and type attributes
Attributes such as aligned, packed, and section modify layout or placement. Example of an 8‑byte aligned struct:
struct qib_user_info {
__u32 spu_userversion;
__u64 spu_base_info;
} __aligned(8);Example of a packed struct that occupies the minimal possible space:
struct test {
char a;
int x[2] __attribute__((packed));
}; // total size = 9 bytesBuilt‑in functions
GCC provides __builtin_* helpers. Notable ones: __builtin_constant_p(x) – returns 1 if x is a compile‑time constant. __builtin_expect(exp,c) – hints that exp is likely to equal c, enabling branch prediction optimizations. Macros LIKELY(x) and UNLIKELY(x) wrap this. __builtin_prefetch(addr, rw, locality) – prefetches data into cache; prefetch() and prefetchw() are kernel wrappers.
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)asmlinkage
On x86, asmlinkage expands to __attribute__((regparm(0))), forcing arguments to be passed on the stack rather than in registers. ARM follows the ATPCS calling convention and does not define asmlinkage.
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))UL suffix
Appending UL to a numeric literal forces it to be of type unsigned long, preventing overflow when the expression would otherwise be evaluated as int.
1 – signed int literal
1UL – unsigned long literal
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
