views:

3933

answers:

6

For example, how to 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
cpp (GCC) 4.1.2 20070626 (Red Hat 4.1.2-14)
A: 

#define TEST_FUN_NAME #FUNC_NAME

see here

shoosh
It doesn't work. See my answer.
J.F. Sebastian
This is indeed incorrect - see also my answer. It is also amazing that it has 4 up votes. The trouble is, it looks like it might be more or less correct, if you aren't thinking carefully.
Jonathan Leffler
+1  A: 
#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
It doesn't work either. See my answer.
J.F. Sebastian
+1  A: 

@Shy: #FUNC_NAME doesn't work

#include <stdio.h>

#ifndef TEST_FUN
#  define TEST_FUN some_func
#  define TEST_FUN_NAME #TEST_FUN
#endif

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

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

It produces compilation error:

make macro_sub && ./macro_sub
cc -std=c99 -Wall    macro_sub.c   -o macro_sub
macro_sub.c: In function ‘main’:
macro_sub.c:16: error: stray ‘#’ in program
macro_sub.c:16: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘void (*)(void)\
’
make: *** [macro_sub] Error 1
J.F. Sebastian
+8  A: 

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);
}
Jonathan Leffler
It works. Thank you. I've posted a working example which reflects the motivation for the code. http://stackoverflow.com/questions/195975/how-to-make-a-char-string-from-a-c-macros-value#196093
J.F. Sebastian
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
A: 

@Jason W: QUOTEME() doesn't work

It prints:

make quoteme &&  ./quoteme
cc -std=c99 -Wall    quoteme.c   -o quoteme
TEST_FUN

But it must print func_name instead of TEST_FUN

J.F. Sebastian
A: 

@Jonathan Leffler: Thank you. Your 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
do something else
TEST_FUN_NAME=another_func
J.F. Sebastian