¿Cómo puedo hacer una cadena de caracteres a partir del valor de una macro C?

3 minutos de lectura

avatar de usuario de jfs
jfs

Por ejemplo, ¿cómo puedo evitar escribir el ‘func_name’ dos veces?

#ifndef TEST_FUN
#  define TEST_FUN func_name
#  define TEST_FUN_NAME "func_name"
#endif

me gustaria seguir el Punto único de la verdad regla.

Versión del preprocesador C:

cpp --version

Producción:

cpp (GCC) 4.1.2 20070626 (Red Hat 4.1.2-14)

  • Posible duplicado de C Macros para crear cadenas

    – Richard Stelling

    06/10/2015 a las 10:34

Avatar de usuario de Jonathan Leffler
jonathan leffler

El que es tímido* te di el germen de una respuesta, pero sólo el germen. La técnica básica para convertir un valor en una cadena en el preprocesador de C es, de hecho, a través del operador ‘#’, pero una simple transliteración de la solución propuesta genera un error de compilación:

#define TEST_FUNC test_func
#define TEST_FUNC_NAME #TEST_FUNC

#include <stdio.h>
int main(void)
{
    puts(TEST_FUNC_NAME);
    return(0);
}

El error de sintaxis está en la línea ‘puts ()’; el problema es un ‘# extraviado’ en la fuente.

En la sección 6.10.3.2 del estándar C, ‘El operador #’, dice:

Cada # token de preprocesamiento en la lista de reemplazo para una macro similar a una función debe ir seguido de un parámetro como el siguiente token de preprocesamiento en la lista de reemplazo.

El problema es que puede convertir argumentos macro en cadenas, pero no puede convertir elementos aleatorios que no sean argumentos macro.

Por lo tanto, para lograr el efecto que buscas, sin duda tienes que hacer un poco de trabajo extra.

#define FUNCTION_NAME(name) #name
#define TEST_FUNC_NAME  FUNCTION_NAME(test_func)

#include <stdio.h>

int main(void)
{
    puts(TEST_FUNC_NAME);
    return(0);
}

No tengo completamente claro cómo planea usar las macros y cómo planea evitar la repetición por completo. Este ejemplo un poco más elaborado podría ser más informativo. El uso de una macro equivalente a STR_VALUE es un modismo necesario para obtener el resultado deseado.

#define STR_VALUE(arg)      #arg
#define FUNCTION_NAME(name) STR_VALUE(name)

#define TEST_FUNC      test_func
#define TEST_FUNC_NAME FUNCTION_NAME(TEST_FUNC)

#include <stdio.h>

static void TEST_FUNC(void)
{
    printf("In function %s\n", TEST_FUNC_NAME);
}

int main(void)
{
    puts(TEST_FUNC_NAME);
    TEST_FUNC();
    return(0);
}

* En el momento en que se escribió esta respuesta por primera vez, el nombre de shoosh usaba ‘Shy’ como parte del nombre.

  • Reescritura casi literal de un comentario hecho originalmente el 2012-10-12 21:37 (que mostraba una negrita función en lugar de __func__) — Por supuesto, en C99, podríamos usar el __func__ identificador predefinido en la función para indicar el nombre de la función. Sin embargo, eso no es ayuda fuera de la función, y ahí es donde realmente se necesita la cadena del nombre de la función.

    –Jonathan Leffler

    29 de diciembre de 2013 a las 18:17

avatar de usuario de jfs
jfs

La solución de Jonathan Leffler funciona.

Un ejemplo de trabajo completo:

/** Compile-time dispatch

   gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub
*/
#include <stdio.h>

#define QUOTE(name) #name
#define STR(macro) QUOTE(macro)

#ifndef TEST_FUN
#  define TEST_FUN some_func
#endif

#define TEST_FUN_NAME STR(TEST_FUN)

void some_func(void)
{
  printf("some_func() called\n");
}

void another_func(void)
{
  printf("do something else\n");
}

int main(void)
{
  TEST_FUN();
  printf("TEST_FUN_NAME=%s\n", TEST_FUN_NAME);
  return 0;
}

Ejemplo:

gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub

Producción:

do something else
TEST_FUN_NAME=another_func

#include <stdio.h>

#define QUOTEME(x) #x

#ifndef TEST_FUN
#  define TEST_FUN func_name
#  define TEST_FUN_NAME QUOTEME(TEST_FUN)
#endif

int main(void)
{
    puts(TEST_FUN_NAME);
    return 0;
}

Referencia: Wikipedia preprocesador C página

¿Ha sido útil esta solución?