Useful C tricks
C
is undoubtedly one of my favorite programming language, as I wrote C code in recent years, I’ve collected several useful C tricks.
Some of ’em taken from popular open source code, you may already know, yet I still hope they can inspire you somehow.
This is an incremental list from time to time, feel free to share with me if you got any.
#1 Unused annotation
/*
* Space between __attribute__ and ( indicates it's not a function call
*
* [sic] <sys/cdefs.h> (from macOS kernel module header)
* __unused denotes variables and functions that may not be used, preventing
* the compiler from warning about it if not used.
*/
#define __unused __attribute__ ((unused))
/**
* Example __unused usage
*/
void foobar(int v __unused)
{
...
}
Yet not all C/C++ compiler support GCC-derived __attribute__
keyword, in such case, you instead define a macro to suppress compiler unused warning:
#define UNUSED(arg, ...) (void) ((void) (arg), ##__VA_ARGS__)
/**
* Example UNUSED usage
*/
void foobar(int v)
{
UNUSED(v);
...
}
#2 Compile-time array size
/**
* Use only for array type, NOT strict pointer type
* @a The fixed size array
*/
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
This macro used widely in Linux kernel and barebox, there’re several known variants, listing above for simplicity.
#3 Compile-time strlen(3)
/**
* Should only used for `char[]' NOT `char *'
* Assume ends with null byte('\0')
*/
#define STRLEN(s) (ARRAY_SIZE(s) - 1)
This macro used for a char
array, it acts as if it called strlen(3), note that it isn’t applicable if the char
array not ends with null byte, i.e. '\0'
.
Since sizeof(char)
always equals to 1, this macro can be further reduce into:
/**
* Should only used for `char[]' NOT `char *'
* Assume ends with null byte('\0')
*/
#define STRLEN(s) (sizeof(s) - 1)
Still, there is a generic STRLEN
to deal the case aforementioned, this macro used rarely since it’s a bit of complicated.
/**
* Should only used for `char[]' NOT `char *'
*/
#define STRLEN(s) (sizeof(s) - !s[sizeof(s)-1])
#4 Explicitly annotate ignore the return value
Case happens when a function return something, yet you don’t care.
For example, you know signal(2) won’t fail in such case:
#include <stdio.h>
#include <signal.h>
int main(void)
{
signal(SIGPIPE, SIG_IGN); /* I don't give it a shit of what signal(2) returns */
...
return 0;
}
Or, you want to implement a microsecond-level sleep(3) function by select(2), and you don’t care about what select(2) pumps out:
#include <sys/select.h>
void usleep(unsigned int us)
{
struct timeval tv = {us / 1000000, us % 1000000};
/* I don't care what select(2) returns although it may got interrupted */
select(0, NULL, NULL, NULL, &tv);
}
Instead of write a comment tell people you don’t care return value(In real life, don’t expected people will do this nice job for you), you can prepend (void)
before function call:
#include <stdio.h>
#include <signal.h>
int main(void)
{
(void) signal(SIGPIPE, SIG_IGN);
...
return 0;
}
#include <sys/select.h>
void usleep(unsigned int us)
{
(void) select(0, NULL, NULL, NULL, (struct timeval[]) {{us / 1000000, us % 1000000}});
}
Note that its usage somewhat like UNUSED
macro, yet it won’t be optimized out, since it’s a function call, in most case it’ll have side-effect, compiler won’t optimize function call out by default, unless your function marked as const
or pure
.
(void) ...
used heavily in FreeBSD kernel, for example, FreeBSD/i386/i386/pmap.c
#5 Compile-time condition assurance
/**
* Compile-time assurance see: linux/arch/x86/boot/boot.h
*/
#define BUILD_BUG_ON(cond) ((void) sizeof(char[1 - 2 * !!(cond)]))
This macro originally taken from Linux source code, yet I optimized it slightly because it’s clumsy.
It mainly used for assuring some conditions, for example:
/* Assure `long' type is 64-bit long */
BUILD_BUG_ON(sizeof(long) != 8);
Any use of BUILD_BUG_ON
macro will eventually be optimized out by the compiler, thus you don’t need to worry about nop execution.
#6 Branch predictions(GCC extension)
/**
* Branch predictions
* see: linux/include/linux/compiler.h
*/
#define likely(x) __builtin_expect(!(x), 0)
#define unlikely(x) __builtin_expect(!(x), 1)
Used heavily in Linux kernel, macro above is slightly different from original form.
[sic] They are hint to the compiler to emit instructions that will cause branch prediction to favour the “likely/unlikely” side of a jump instruction.
Compiler will optimize the code according to branch prediction, for examplem, if you have something like this:
char *istrdup(const char *s)
{
size_t sz = strlen(s) + 1;
char *p = (char *) malloc(sz);
if (unlikely(p == NULL)) goto out_exit;
(void) strcpy(p, s);
out_exit:
return p;
}
The compiler may happen to optimize your code into the following form, which its code path is more likely be a pipeline instead of a jumpline:
char *istrdup(const char *s)
{
size_t sz = strlen(s) + 1;
register char *p = (char *) malloc(sz);
if (likely(p != NULL)) {
(void) strcpy(p, s);
}
return p;
}
Note that inverted prediction will cause CPU pipeline flush, it’s better not to use branch prediction instead of using wrong one to cause performance degradation, especially in hot code path.
#7 Side-effect-safe MIN
, MAX
, ABS
macro(GCC extension)
#define MIN(a, b) ({ \
__typeof(a) _a = (a); \
__typeof(b) _b = (b); \
_a < _b ? _a : _b; \
})
#define MAX(a, b) ({ \
__typeof(a) _a = (a); \
__typeof(b) _b = (b); \
_a > _b ? _a : _b; \
})
#define ABS(x) ({ \
__typeof(x) _ = (x); \
_ > 0 ? _ : -_; \
})
Those three are common used math macros, which they’re all type-agnostic, and eliminated possible side-effects, it uses GCC typeof keyword.
#8 Sizeof a struct’s member
#define STRUCT_MEMBER_SIZEOF(s, m) sizeof((*((s[0]){})).m)
Used to get sizeof
result inside a struct, without intervention of a struct variable, i.e. struct_var.some_member
.
For example, if you want to bind(2) a socket with a name(path), you should check if given path
length exceeds struct sockaddr_un.sun_path
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#define STRUCT_MEMBER_SIZEOF(s, m) sizeof((*((s[0]){})).m)
/**
* Create a named socket(trivial implementation)
* @path The socket name [XSI]
* @return file descriptor returned if success
* -1 if failed(errno will be set accordingly)
*/
int create_named_socket(const char *path)
{
/* XXX: Use of STRUCT_MEMBER_SIZEOF macro */
static size_t LIMIT = STRUCT_MEMBER_SIZEOF(struct sockaddr_un, sun_path);
int fd = -1;
size_t len;
struct sockaddr_un sun;
assert(path != NULL);
len = strlen(path);
/* struct sockaddr_un.sun_path[10x] */
if (len >= LIMIT) {
errno = ENAMETOOLONG;
fprintf(stderr, "Path %s too long %zu vs %zu\n", path, len, LIMIT);
goto out_exit;
}
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "socket(2) fail errno: %d\n", errno);
goto out_exit;
}
sun.sun_family = AF_UNIX;
(void) strcpy(sun.sun_path, path);
#if defined(__APPLE__) || defined(BSD)
sun.sun_len = (unsigned char) SUN_LEN(&sun);
#endif
if (bind(fd, (struct sockaddr *) &sun, sizeof(sun)) < 0) {
fprintf(stderr, "bind(2) fail fd: %d path: %s errno: %d\n", fd, path, errno);
goto out_fail;
}
if (listen(fd, SOMAXCONN) < 0) {
fprintf(stderr, "listen(2) fail fd: %d path: %s errno: %d\n", fd, path, errno);
goto out_fail;
}
printf("socket created fd: %d path: %s\n", fd, path);
out_exit:
return fd;
out_fail:
(void) close(fd);
fd = -1;
goto out_exit;
}
Wrap up
leiless/assertf.h is a C assertion library(header-only), which enhanced compile-time/runtime assertions, it also included some frequently used macros aforementioned.
leiless/dbg.h is a runtime code path tracing library for C89, a cheap replica of sharkdp/dbg-macro.
References
GCC is wonderful: a better ARRAY_SIZE macro
MagicMacros - Linux Kernel Newbies
__attribute__((const)) vs __attribute__((pure)) in GNU C