Outils pour utilisateurs

Outils du site


lang:c:preprocesseur

Convertir un nombre en chaîne de caractères

cpp/preprocessor/str_helper.h
#pragma once
 
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

Exemple d'utilisation :

cpp/preprocessor/str_helper.cpp
#include "str_helper.h"
#define VERSION STR(3) "." STR(2) "." STR(1)
static const char* version __attribute__((unused)) = VERSION;
int main() {}

Rendu :

cpp/preprocessor/str_helper.cpp.i
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

Ecrire un commentaire dans une macro multi lignes

#define SOME_BIG_MACRO(input)\
  SOME_FUNCTION_CALL()  /* this does... */ \
  SOME_OTHER_FUNCTION_CALL()

Forcer le ; après une macro

Chaque ligne de code doit se terminer par un ;.

Cela peut poser problème avec certaines macros.

  • Deux lignes de code
#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

  • Une fonction complète

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

Détection du compilateur

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

Détection de l'OS

  • Windows : _WIN32,
  • Windows 64 bit : _WIN64,
  • Linux : __linux__,
  • Android : __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

Risque du coding style (espace avant parenthèse)

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 :

cpp/preprocessor/macro_and_spaces.cpp
#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 :

cpp/preprocessor/macro_and_spaces.cpp.i
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.

lang/c/preprocesseur.txt · Dernière modification : 2024/04/09 15:21 de root