#pragma once #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x)
Exemple d'utilisation :
#include "str_helper.h" #define VERSION STR(3) "." STR(2) "." STR(1) static const char* version __attribute__((unused)) = VERSION; int main() {}
Rendu :
static const char* version __attribute__((unused)) = "3" "." "2" "." "1"; int main() {}
C Preprocessor_ concatenate int to string - Stack Overflow Archive du 28/03/2011 le 17/10/2019
#define SOME_BIG_MACRO(input)\
SOME_FUNCTION_CALL() /* this does... */ \
SOME_OTHER_FUNCTION_CALL()
Chaque ligne de code doit se terminer par un ;
.
Cela peut poser problème avec certaines macros.
#define SKIP_SPACES(p, limit) \ { char *lim = (limit); \ while (p < lim) { \ if (*p++ != ' ') { \ p--; break; }}} if (*p != 0) SKIP_SPACES (p, lim); else
Problème : il y a un ;
après un }
.
Solution : do{} while (0);
.
#define SKIP_SPACES(p, limit) \
do { char *lim = (limit); \
while (p < lim) { \
if (*p++ != ' ') { \
p--; break; }}} \
while (0)
Swallowing the Semicolon Archive du 2002 le 09/04/2024
Problème :
#define MACRO() \
void foo(){}
Solution : static_assert
.
#ifdef __cplusplus #include <cassert> #else #include <assert.h> #endif #define MACRO() \ void foo(){} \ static_assert(true, "") MACRO();
How to require a semicolon after a macro Archive du 21/02/2016 le 09/04/2024
Note : sous clang
et le compilateur d'Intel, __GNUC__
est défini.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-truncation" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdocumentation" #endif #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4242) #endif ... #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) #pragma GCC diagnostic pop #endif #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef _MSC_VER #pragma warning(pop) #endif
How to tell Clang to stop pretending to be other compilers? Archive du 21/07/2016 le 14/10/2022
_WIN32
,_WIN64
,__linux__
,__ANDROID__
.Operating Systems Archive du 18/10/2022 le 23/01/2023
Cas courant :
#if defined(_WIN32) #elif __APPLE__ #elif __ANDROID__ #elif __linux__ #else # error "Unknown compiler" #endif
Note : Apple définit également __linux__
. Il faut donc vérifier en premier defined(__APPLE__)
si on veut faire une distinction entre les deux.
How do I check OS with a preprocessor directive? Archive du 26/09/2008 le 23/01/2023
Si on souhaite faire passer des arguments à la macro, il est nécessaire que la parenthèse touche le nom de la macro. Sinon, le préprocesseur interprétera la parenthèse comme le début du remplacement.
Exemple :
#define RET_NEG (ARG1) - ARG1; int main() { int ARG1 = 1; // Interprétation erronée à cause de l'espace après ADD lors de la définition de la macro. // cppcheck-suppress unreachableCode // cppcheck-suppress constStatement return RET_NEG(ARG1); }
Rendu :
int main() { int ARG1 = 1; return (ARG1) - ARG1;(ARG1); }
Heureusement, l'erreur est presque toujours détectée à la compilation mais elle peut être difficilement trouvée. C'est pour cette raison que je déconseille l'utilisation d'un espace avant les parenthèses comme règle de codage.