59

For example, how can I avoid writing the 'func_name' twice?

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

I'd like to follow the Single Point of Truth rule.

Version of C preprocessor:

cpp --version

Output:

cpp (GCC) 4.1.2 20070626 (Red Hat 4.1.2-14)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jfs
  • 399,953
  • 195
  • 994
  • 1,670

3 Answers3

88

He who is Shy* gave you the germ of an answer, but only the germ. The basic technique for converting a value into a string in the C pre-processor is indeed via the '#' operator, but a simple transliteration of the proposed solution gets a compilation error:

#define TEST_FUNC test_func
#define TEST_FUNC_NAME #TEST_FUNC

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

The syntax error is on the 'puts()' line - the problem is a 'stray #' in the source.

In section 6.10.3.2 of the C standard, 'The # operator', it says:

Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter as the next preprocessing token in the replacement list.

The trouble is that you can convert macro arguments to strings -- but you can't convert random items that are not macro arguments.

So, to achieve the effect you are after, you most certainly have to do some extra work.

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

I'm not completely clear on how you plan to use the macros, and how you plan to avoid repetition altogether. This slightly more elaborate example might be more informative. The use of a macro equivalent to STR_VALUE is an idiom that is necessary to get the desired result.

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

* At the time when this answer was first written, shoosh's name used 'Shy' as part of the name.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Almost verbatim rewrite of a comment originally made 2012-10-12 21:37 (which showed a bold __func__ instead of `__func__`) — Of course, in C99, we could use the `__func__` pre-defined identifier in the function to mean the function name. However, that is no help outside the function, and that's where the function name string is really needed. – Jonathan Leffler Dec 29 '13 at 18:17
21

Jonathan Leffler's solution works.

A complete working example:

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

Example:

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

Output:

do something else
TEST_FUN_NAME=another_func
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jfs
  • 399,953
  • 195
  • 994
  • 1,670
0
#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;
}

Reference: Wikipedia's C preprocessor page

Jason Weathered
  • 7,762
  • 2
  • 41
  • 37