c_advanced_tips_n_tricks

42 conference about some C tricks
Log | Files | Refs | git clone https://git.ne02ptzero.me/git/c_advanced_tips_n_tricks

commit 97a5e13f4e1f172359ed1bb3d23da608bf26ffe5
Author: Louis Solofrizzo <lsolofrizzo@online.net>
Date:   Thu, 18 Oct 2018 16:59:52 +0200

Add: Presentation & Code

Signed-off-by: Louis Solofrizzo <lsolofrizzo@online.net>

Diffstat:
Ac_advanced_presentation.md | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acompilation_magics/Makefile | 36++++++++++++++++++++++++++++++++++++
Acompilation_magics/container_of.c | 33+++++++++++++++++++++++++++++++++
Acompilation_magics/count_of.c | 16++++++++++++++++
Acompilation_magics/functionnal.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Acompilation_magics/named_parameters.c | 23+++++++++++++++++++++++
Acompilation_magics/named_struct_param.c | 38++++++++++++++++++++++++++++++++++++++
Acompilation_magics/offsetof.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Acompilation_magics/printf_function.c | 19+++++++++++++++++++
Acompilation_magics/quote.c | 16++++++++++++++++
Acompilation_magics/static_array_foreach.c | 21+++++++++++++++++++++
Acompilation_magics/static_assert.c | 27+++++++++++++++++++++++++++
Acompilation_magics/typeof.c | 14++++++++++++++
Acompilation_magics/unused.c | 12++++++++++++
14 files changed, 640 insertions(+), 0 deletions(-)

diff --git a/c_advanced_presentation.md b/c_advanced_presentation.md @@ -0,0 +1,287 @@ +%title: C & System +%author: Louis + +C & System +========== + +- **C 'Advanced' Tips & Tricks + - Compilation Magics + - What is slow? + - free() the malloc! + +--- + +# Compilation Magics + + COUNT_OF(ptr) + +Determine size of an array __at__ compilation + + #define COUNT_OF(ptr) (sizeof(ptr) / sizeof((ptr)[0])) + +--- + +# Compilation Magics + + UNIQ + +Use an unique name for a variable + + #define ___UNIQ(name, n) name##n + #define __UNIQ(name, n) ___UNIQ(name, n) + #define _UNIQ(name, n) __UNIQ(name, n) + #define UNIQ(name) _UNIQ(name, __LINE__) + +--- + +# Compilation Magics + + STATIC_ARRAY_FOREACH + +Process an array statically + + #define STATIC_ARRAY_FOREACH(item, array) \ + for (size_t keep = 1, index = 0; \ + keep && index < COUNT_OF(array); \ + keep = !keep, index++) \ + for (item = &array[index]; keep; keep = !keep) + +--- + +# Compilation Magics + + (c11) _Static_assert + +or + + STATIC_ASSERT + +Raise an error with something that can be computed at compilation + + #define STATIC_ASSERT(COND, MSG) typedef char \ + static_assertion_##MSG[(COND) ? 1 : -1] + +--- + +# Compilation Magics + + STR(str) + +Quote anything at compilation + + #define QUOTE_ME(x) #x + #define STR(x) QUOTE_ME(x) + +--- + +# Compilation Magics + + __printf_function(X, X) + +Tells the compiler to use the printf's format for this function + + #define __printf_function(...) __attribute__((format (printf, __VA_ARGS__))) + +--- + +# Compilation Magics + + likely(x) + unlikely(x) + +Inform the compiler about the probability of a condition + + #define likely(x) __builtin_expect((x), 1) + #define unlikely(x) __builtin_expect((x), 0) + +--- + +# Compilation Magics + + __hot_function + __cold_function + +Inform the compiler about functions that are called often or not + + #define __hot_function __attribute__((hot)) + #define __cold_function __attribute__((cold)) + +--- + +# Compilation Magics + + __const_function + __noreturn_function + __non_null_arguments + __pure_function + +Functionnal paradigms in C + + #define __const_function __attribute__((const)) + #define __noreturn_function __attribute__((noreturn)) + #define __non_null_arguments __attribute__((nonnull)) + #define __pure_function __attribute__((pure)) + +--- + +# Compilation Magics + + __unused + +Tells the compiler that a function variable is not used + + #define __unused __attribute__((unused)) + +--- + +# Compilation Magics + + inline + __attribute__((always_inline)) + +Inline a function + +--- + +# Compilation Magics + + volatile + +Tels the compiler _not to_ CPU cache this variable + +--- + +# Compilation Magics + +Named structure parameters + + struct a { + int b; + int c; + }; + + [...] + struct a my_struct = { .b = 10, .c = 40 }; + +--- + +# Compilation Magics + +Optionnal named parameters in C + + my_function(arg_required_1, arg_required_2, .some_opt_arg = 1); + +--- + +# Compilation Magics + + offsetof(TYPE, MEMBER) + +Determine the offset of a struct member at compilation + + #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) + +--- + +# Compilation Magics + + typeof(member) + +Determine the type of a variable at compilation + +--- + +# Compilation Magics + + #define container_of(ptr, type, type2, member) + +Determine the parent structure from a pointer at compilation + + #define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +--- + +# What is slow? (Baby don't hurt me) + +Cost of common computing operations + +--- + +# What is slow?: CPU Operations + +|----------------------------------|-------------| +| **Operation** | **Light speed** | +|----------------------------------|-------------| +| Register OP | < 5cm | +| Memory Write | ~ 5cm | +| Right prediction for a condition | ~ 10cm | +| Floating point addition | ~ 15cm | +| Multiplication | ~ 30cm | +| L1 Read | ~ 30cm | +| L2 Read | ~ 1m | +| Wrong prediction for a condition | ~ 1m50 | +| Floating point division | ~ 2m | +| C function call | ~ 2m | +| Integer division | ~ 2m | +| RAM Read | ~ 50m | +| Kernel Call | ~ 600m | +| Context switch | ~ 30km | +|----------------------------------|-------------| +| HDD SATA Disk IO | ~ 150 000km | +|----------------------------------|-------------| + +--- + +# What is slow?: Syscalls + +Userspace + + Program -> Syscall! -> CPU + +Kernel + + Interruption Table -> Interruption: Syscall! -> Treatment + Treatment -> Interruption Table -> We got a return! -> CPU + +Userspace + + Waiting on a return -> CPU return ! -> Carry on + +--- + +# What is slow?: VLAs + + void function(int size) + { + char str[size] = { 0 }; + + ... + sizeof(str) ? + } + +--- + +# free() the malloc! + +- Why free() ? +- What is a memory leak? +- Can malloc() fail? + +--- + +# Thank you! + + ------------ + < Questions? > + ------------ + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || + +This presentation and the code are open source: + +https://git.ne02ptzero.me/Presentation_C_Advanced_Tips_n_Tricks diff --git a/compilation_magics/Makefile b/compilation_magics/Makefile @@ -0,0 +1,36 @@ +CC = gcc +CFLAGS = -Wall -Wextra -Werror -include stdio.h -include stdint.h -std=c99 + +count_of: count_of.o + $(CC) $(CFLAGS) $@.o -o $@ + +static_assert: static_assert.o + $(CC) $(CFLAGS) $@.o -o $@ + +quote: quote.o + $(CC) $(CFLAGS) $@.o -o $@ + +offsetof: offsetof.o + $(CC) $(CFLAGS) $@.o -o $@ + +static_array_foreach: static_array_foreach.o + $(CC) $(CFLAGS) $@.o -o $@ + +printf_function: printf_function.o + $(CC) $(CFLAGS) $@.o -o $@ + +named_struct_param: named_struct_param.o + $(CC) $(CFLAGS) $@.o -o $@ + +typeof: typeof.o + $(CC) $(CFLAGS) $@.o -o $@ + +container_of: container_of.o + $(CC) $(CFLAGS) $@.o -o $@ + +named_parameters: named_parameters.o + $(CC) $(CFLAGS) $@.o -o $@ + +clean: + rm -f *.o + rm -f count_of static_assert quote offsetof static_array_foreach printf_function named_struct_param typeof container_of named_parameters diff --git a/compilation_magics/container_of.c b/compilation_magics/container_of.c @@ -0,0 +1,33 @@ +#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) +#define typeof __typeof__ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +typedef struct { + int val; +} a_t; + +typedef struct { + a_t a; + int b; +} b_t; + +void function(a_t *ptr) +{ + b_t *parent = container_of(ptr, b_t, a); + printf("%d\n", parent->b); +} + +int main(void) +{ + b_t b = { + .b = 42, + .a = { + .val = 12 + } + }; + + function(&b.a); + return 0; +} diff --git a/compilation_magics/count_of.c b/compilation_magics/count_of.c @@ -0,0 +1,16 @@ +#include <stdio.h> +#define COUNT_OF(ptr) (sizeof(ptr) / sizeof((ptr)[0])) + +int main(void) +{ + static const char *strings[] = { + "Hello", + "World", + NULL + }; + + for (size_t i = 0; strings[i] != NULL; i++) + printf("Value is = %s\n", strings[i]); + + return 0; +} diff --git a/compilation_magics/functionnal.c b/compilation_magics/functionnal.c @@ -0,0 +1,45 @@ +#define __const_function __attribute__((const)) +#define __noreturn_function __attribute__((noreturn)) +#define __non_null_arguments __attribute__((nonnull)) +#define __pure_function __attribute__((pure)) + +/*! + * Pure function: + * Can only return a value + */ +__pure_function +int pure_function(char arg) +{ + return some_global_array[arg]; +} + +/*! + * Const function: + * Like pure, but this function cannot read global memory + */ +__const_function +int const_function(int a, int b) +{ + return a * b; +} + +/*! + * The compiler will check if there is some cases where this function + * can be called with a null parameter, and throw an error + */ +__non_null_arguments +void non_null_function(uintptr_t *ptr) +{ + return ; +} + +/*! + * No Return: + * This function can't return anything, and won't, ever + * (Infinite loop, exit() functions, ...) + */ +__noreturn_function +void exit_function(void) +{ + exit(1); +} diff --git a/compilation_magics/named_parameters.c b/compilation_magics/named_parameters.c @@ -0,0 +1,23 @@ +typedef struct { + int do_print; + char *name; +} some_function_args_t; + +void some_function(int required_a, int required_b, some_function_args_t *args) +{ + printf("required_a = %d\n", required_a); + printf("required_b = %d\n", required_b); + printf("opt.do_printf = %d\n", args->do_print); + printf("opt.name = %s\n\n", args->name); +} +#define some_function(a, b, ...) \ + some_function(a, b, &(some_function_args_t){__VA_ARGS__}) + +int main(void) +{ + some_function(1, 2); + some_function(1, 2, .do_print = 1); + some_function(1, 2, .name = "Louis"); + some_function(1, 2, .name = "Louis", .do_print = 3); + return 0; +} diff --git a/compilation_magics/named_struct_param.c b/compilation_magics/named_struct_param.c @@ -0,0 +1,38 @@ +#include <stdbool.h> +#define COUNT_OF(ptr) (sizeof(ptr) / sizeof((ptr)[0])) +#define STATIC_ARRAY_FOREACH(item, array) \ + for (size_t keep = 1, index = 0; \ + keep && index < COUNT_OF(array); \ + keep = !keep, index++) \ + for (item = &array[index]; keep; keep = !keep) + +typedef struct { + char *val; + int a; + bool c; +} some_t; + +static const some_t global[] = { + { + .val = "Alu!", + .a = 2 + }, + { + .c = true + }, + { + .a = 10 + } +}; + +int main(void) +{ + STATIC_ARRAY_FOREACH(const some_t *ptr, global) + { + printf("Entry:\n"); + printf("\tval = %s\n", ptr->val); + printf("\ta = %d\n", ptr->a); + printf("\tc = %s\n", ptr->c ? "true" : "false"); + } + return 0; +} diff --git a/compilation_magics/offsetof.c b/compilation_magics/offsetof.c @@ -0,0 +1,53 @@ +#define COUNT_OF(ptr) (sizeof(ptr) / sizeof((ptr)[0])) +#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) + +typedef struct { + const char *one; + const char *two; + const char *three; +} struct_t; + +static void array_to_struct(const char **str, size_t size, struct_t *out) +{ + for (size_t i = 0; i < size; i++) + { + if (i == 0) + out->one = str[i]; + else if (i == 1) + out->two = str[i]; + else if (i == 2) + out->three = str[i]; + } +} + +/*static void array_to_struct(const char **str, size_t size, struct_t *out)*/ +/*{*/ + /*size_t offsets[] = {*/ + /*[0] = offsetof(struct_t, one),*/ + /*[1] = offsetof(struct_t, two),*/ + /*[2] = offsetof(struct_t, three)*/ + /*};*/ + + /*for (size_t i = 0; i < size; i++)*/ + /*{*/ + /*uintptr_t ptr = (uintptr_t)out + (uintptr_t)offsets[i];*/ + /*const char **tmp = (const char **)ptr;*/ + + /**tmp = str[i];*/ + /*}*/ +/*}*/ + +int main(void) +{ + struct_t strct = { 0 }; + static const char *str[] = { + "ONE", "TWO", "THREE" + }; + + array_to_struct(str, COUNT_OF(str), &strct); + printf("struct.one = %s\n", strct.one); + printf("struct.two = %s\n", strct.two); + printf("struct.three = %s\n", strct.three); + + return 0; +} diff --git a/compilation_magics/printf_function.c b/compilation_magics/printf_function.c @@ -0,0 +1,19 @@ +#include <stdarg.h> +#define __printf_function(...) __attribute__((format (printf, __VA_ARGS__))) + +static void custom_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); +} + +int main(void) +{ + int val = 10; + + custom_log("Value is %d\n", val); + return 0; +} diff --git a/compilation_magics/quote.c b/compilation_magics/quote.c @@ -0,0 +1,16 @@ +#define QUOTE_ME(x) #x +#define STR(x) QUOTE_ME(x) + +#define MAX_ARGC 3 + +int main(int ac, const char **av) +{ + if (ac > MAX_ARGC) + { + printf("Maximum argc number is: %d\n", MAX_ARGC); + return 1; + } + + printf("All good! %s\n", av[1]); + return 0; +} diff --git a/compilation_magics/static_array_foreach.c b/compilation_magics/static_array_foreach.c @@ -0,0 +1,21 @@ +#define COUNT_OF(ptr) (sizeof(ptr) / sizeof((ptr)[0])) +#define STATIC_ARRAY_FOREACH(item, array) \ + for (size_t keep = 1, index = 0; \ + keep && index < COUNT_OF(array); \ + keep = !keep, index++) \ + for (item = &array[index]; keep; keep = !keep) + +int main(void) +{ + const char *str[] = { + "Hello", + "World!" + }; + + STATIC_ARRAY_FOREACH(const char **ptr, str) + { + printf("%s\n", *ptr); + } + + return 0; +} diff --git a/compilation_magics/static_assert.c b/compilation_magics/static_assert.c @@ -0,0 +1,27 @@ +#define COUNT_OF(ptr) (sizeof(ptr) / sizeof((ptr)[0])) + +typedef enum { + OPTION_ONE = 0, + OPTION_TWO, + OPTION_THREE +} option_t; + +const char *option_to_str(option_t opt) +{ + static const char *str[] = { + [OPTION_ONE] = "ONE", + [OPTION_TWO] = "TWO", + [OPTION_THREE] = "THREE", + }; + + return str[opt]; +} + +int main(void) +{ + printf("OPTION_ONE: %s\n", option_to_str(OPTION_ONE)); + printf("OPTION_TWO: %s\n", option_to_str(OPTION_TWO)); + printf("OPTION_THREE: %s\n", option_to_str(OPTION_THREE)); + + return 0; +} diff --git a/compilation_magics/typeof.c b/compilation_magics/typeof.c @@ -0,0 +1,14 @@ +#define typeof __typeof__ +#define auto(n, val) typeof(val) n = val + +int main(void) +{ + int a; + typeof(a) b = 10; + + auto(c, 150); + + printf("%d\n", b); + printf("%d\n", c); + return 0; +} diff --git a/compilation_magics/unused.c b/compilation_magics/unused.c @@ -0,0 +1,12 @@ +#define __unused __attribute__((unused)) + +void some_function(int arg1, int arg2) +{ + printf("arg1 = %d\n", arg1); +} + +int main(void) +{ + some_function(1, 2); + return 0; +}