Table des matières

Langage C

La page de man de GCC est dans le paquet gcc-doc.

Obtenir le nom d'hôte de la machine

#include <unistd.h>
 
char hostname[20];
gethostname(hostname, 20);

Générer un nombre aléatoire

Entre 0 et 1:

#include <stdlib.h> // rand() et RAND_MAX
#include <time.h>
 
srand(time(NULL));
 
float x = rand() / ((float) RAND_MAX); 

Entre 0 et n (exclu):

#include <stdlib.h> // rand() et RAND_MAX
#include <time.h>
 
srand(time(NULL));
 
unsigned x = rand() % n;

Instructions au compilateur

#warning qchose // provoque un warning à la compilation
#error qchose // provoque une erreur à la compilation

Capturer une chaîne de caractère jusqu'au retour à la ligne

sscanf(string, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version);

Le sélecteur %[^\n] ne capture pas le \n.

Déclarer des variables dans des headers

Source

Si on déclare et définit une variable dans un fichier d'en-tête, le linker peut rapidement générer des erreurs du type first defined here, alors qu'il pointe l'endroit de la définition.

Pour résoudre ce problème, on déclare la variable dans l'en-tête et on la définit dans le fichier source:

// .h
extern const int N_MAX;
 
//.c
const int N_MAX = 1000;

(à voir si c'est vraiment du code propre…)

Attributs GCC

Variable inutilisée

Source

static int trace_loop __attribute__((unused)) = 0;

Ne pas optimiser une fonction

float __attribute__((optimize("O0"))) scalar_avx_product(float* a, float* b)

Effacer une ligne affichée à l'écran

Source

Convertir une chaîne de caractères en entier

C'est la fonction atoi !

Préprocesseur

Utiliser un paramètre dans une chaîne de caractère

#define PSQR(x) printf("The square of " #x " is %d.\n",((x)*(x)))
 
PSQR(y); // The square of y is 25.
#define FORMAT "%04d"
 
printf("Value: "FORMAT"\n", value);

(source)

Utiliser un paramètre comme préfixe

#define MY_VAR(var) int var##_my;
 
MY_VAR(truc) // truc_my;

Pointeurs et constantes

int *const ptr = &var1; // l'adresse stockée dans ptr est constante
ptr = &var2; // interdit
 
const int* ptr = &var1; // la valeur à l'adresse stockée dans ptr est constante
*ptr = 1; // interdit
 
// possibilité d'utiliser les deux en même temps:
const int* const ptr = &var1;
*ptr = 1; // interdit
ptr = &var2; // interdit

Incrémentations

int i = 2;
int j = i++;
// j = 2 et i = 3
// retourne la valeur initiale et incrémente ensuite
 
i = 2;
int k = ++i;
// k = i = 3
// retourne la valeur incrémentée

Constantes de préprocesseur

Epsilon flottant

C'est la constante FLT_EPSILON pour les float ou DBL_EPSILON pour les double, définies dans le fichier d'en-tête float.h (source).

Pi

M_PI dans math.h

Connaître toutes les constantes définies par GCC

gcc -march=native -dM -E - </dev/null

Threads

Binder un thread sur un coeur

Sans hwloc, utiliser pthread_setaffinity_np().

En ligne de commande:

taskset -c 0 bash

Nommer un thread

#define _GNU_SOURCE // au tout début du fichier
 
// ...
 
pthread_setname_np(pthread_self(), "Thread foo");

Le nom du thread est limité à 15 caractères. Cette fonction n'est pas portable.

Formats de printf

Ajouter un certain nombre de zéros en préfixe (et ne pas les afficher si le nombre est suffisamment grand): %02d (pour 5 affiche 05 et pour 15 affiche 15). On peut se servir de cette technique pour forcer un espace si le nombre est positif et remplacer cet espace par le signe négatif sinon: % 2d. Dans le cas où on a toujours le même signe, le caractère espace n'est pas nécessaire.

Tester l'architecture

#if defined(__x86_64__)
printf("x86_64 !\n");
#else
printf("autre\n");
#endif

Voir https://sourceforge.net/p/predef/wiki/Architectures/ pour une liste de possibilités.

Il y a aussi cette page qui permet de tester plein de choses.

Ce mémo est aussi intéressant.

Désactiver les asserts

Déclarer la variable de préprocesseur NDEBUG avant l'inclusion de assert.h (source)

Tester si l'entrée standard est une redirection

Source

#include <stdio.h>
#include <io.h>
 
if (isatty(fileno(stdin)))
    printf("stdin is a terminal\n");
else
    printf("stdin is a file or a pipe\n");

_Generic

Vérifier les accès mémoires sur la pile

Compiler avec l'option –fstack-protector-all. L'option -fsanitize=address aide aussi.

Récupérer toutes les variables d'environnement

Afficher la pile d'appels

Source

#include <execinfo.h> /* backtrace, backtrace_symbols_fd */
#include <unistd.h> /* STDOUT_FILENO */
 
void print_stacktrace(void) {
    size_t size;
    enum Constexpr { MAX_SIZE = 1024 };
    void *array[MAX_SIZE];
    size = backtrace(array, MAX_SIZE);
    backtrace_symbols_fd(array, size, STDOUT_FILENO);
}

On peut ensuite connaître la ligne du fichier source correspondant à l'adresse donnée dans la pile d'appels avec :

addr2line -e main.out 0x4007db
#!/bin/bash
 
readonly BACKTRACE_FILE=$1
 
for l in $(grep -E "^/.+\(.+\)\[.+\]" $BACKTRACE_FILE)
do
	lib=$(echo $l | sed -E "s/(\/.+)\(.+/\1/g")
	addr=$(echo $l | sed -E "s/.+\((.+)\).+/\1/g")
	ans=$(addr2line -e $lib $addr)
	if [[ $ans == "??"* ]]
	then
		echo $l
	else
		echo $ans
	fi
done

Voir le code source produit après le passage du préprocesseur

gcc -E source.c

Assembleur

Toujours colorier les messages de GCC

Ajouter l'option -fdiagnostics-color=always à la commande gcc (source).

ifunc

Mécanisme qui permet de choisir quelle fonction associer à un symbole lors de la résolution des symboles lors du lancement d'un binaire.

Gestion des caractères non-ASCII

Fichiers de suppressions pour sanitizers

Dans un fichier asan.supp :

leak:libdbus-1.so
LSAN_OPTIONS=suppressions=asan.supp,print_suppressions=0 ./programme