Как сделать символьную строку из значения макроса C? - PullRequest
47 голосов
/ 13 октября 2008

Например, как избежать написания 'func_name' дважды?

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

Я бы хотел следовать правилу Единой точки истины .

Версия препроцессора C:

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

Ответы [ 4 ]

69 голосов
/ 13 октября 2008

Тот, кто застенчив * дал вам зародыш ответа , но только зародыш. Основная методика преобразования значения в строку в препроцессоре C действительно заключается в использовании оператора «#», но простая транслитерация предложенного решения приводит к ошибке компиляции:

#define TEST_FUNC test_func
#define TEST_FUNC_NAME #TEST_FUNC

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

Синтаксическая ошибка находится в строке put () - проблема в том, что в источнике есть "заблудившийся #".

В разделе 6.10.3.2 стандарта C «Оператор #» говорится:

Каждый # токен предварительной обработки в список замены для подобной функции макрос должен сопровождаться параметром в качестве следующего токена предварительной обработки в список замены.

Беда в том, что вы можете преобразовывать макро-аргументы в строки, но вы не можете конвертировать случайные элементы, которые не являются макро-аргументами.

Итак, чтобы достичь желаемого эффекта, вам наверняка придется проделать дополнительную работу.

#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);
}

Мне не совсем понятно, как вы планируете использовать макросы и как вы планируете вообще избегать повторения. Этот немного более сложный пример может быть более информативным. Использование макроса, эквивалентного STR_VALUE, - это идиома, необходимая для получения желаемого результата.

#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);
}

* В то время, когда этот ответ был впервые написан, имя shoosh использовало 'Shy' как часть имени.

14 голосов
/ 13 октября 2008

@ Джонатан Леффлер: Спасибо. Ваше решение работает.

Полный рабочий пример:

/** 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;
}

Пример:

$ gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub
do something else
TEST_FUN_NAME=another_func
0 голосов
/ 13 октября 2008
#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;
}

Ссылка: препроцессор C Википедии страница

0 голосов
/ 13 октября 2008

#define TEST_FUN_NAME #FUNC_NAME

см. здесь

...