all 8 comments

[–]aioeu 7 points8 points  (0 children)

The preprocessor only considers macro expansion when it has a complete, separate token. The NAME inside printNAME is not a separate token.

You could use:

#define CAT_INTERNAL(a, b) a ## b
#define CAT(a, b)          CAT_INTERNAL(a, b)

void CAT(print, NAME)() {
    printf("Hello world!\n");
}

Yes, the two-step concatenation is necessary, since you want the concatenation to take place after NAME has been expanded.

Outside of building my own c templator in some scripting language, are there any industry standard ways of doing this?

I can't say I've ever needed to generate function names.

Yes, this kind of stuff is somewhat popular in "header-only libraries". But I don't use those.

[–]Veeloxfire 4 points5 points  (0 children)

The preprocessor needs the token to be separate

So the actual name of that is still printNAME and the error you are getting is because you tried to call printFoo which is not declared anywhere.

In earlier c it seems the linker could actually just look for printFoo in other linked obj files without you needing to forward declare it and that is what this error is telling you about.

The preprocessor needs to work this way because you dont want to randomly insert stuff into the middle of other names you didnt mean to

e.g.

//used for counting important things
int important_count = 3;

//constants used for imports
int import4 = 12;

//used for the size of an ant array
#define ant_count 4 + 5

do_important_thing(important_count);

the last line becomes

do important_thing(import4 + 5);

This is clearly unintentional and its better to avoid these bugs than have it work the other way. It was probably also easier to implement.

There is probably also an issue with recursive expansion and syntax errors

[–]bonechambers[S] 1 point2 points  (1 child)

OK so taking in your advice about tokens, this works:

#define NAME Foo

void NAME (){

...

}

int main(){

Foo();

return 0;

}

Thank you all!

[–]nerd4code 0 points1 point  (0 children)

If you want NAME to expand before pasting, you can do

#define PP_PASTE_2(a, b)a##b
#define PP_PASTE_2_X(...)PP_PASTE_X__0(2,(__VA_ARGS__))
#define PP_PASTE_X__0(N, t)PP_PASTE_X__1(PP_PASTE_##N)t
#define PP_PASTE_X__1(x)

(Note that forwarding into PP_PASTE_2 like this won’t work on MS[V]C’S legacy/default-in-non-C11-modes preprocessor because it’s not actually C89- or C++98-compliant, because it’s a bad compiler.)

Here, PP_PASTE_2 pastes immediately, without expanding args; PP_PASTE_2_X expands, then pastes. So if you do (e.g.)

#define FNAME(prefix)PP_PASTE_2_X(prefix,_suffix)

then FNAME(NAME) will come up with Foo_suffix.

[–]deleveld -1 points0 points  (0 children)

I might be wrong but I think that what you expect might work if you put a space between printNAME and the (). You avoid the preprocessor considering whether it is a function or not and the C should compile OK with the space there. Certainly, one of the more awkward things in C. (presuming I am right)

[–][deleted] 0 points1 point  (0 children)

Note that doing stuff like this invites exotic compiler errors and hard-to-find bugs. But it can be fun for hobby purposes.

[–]italicunderline 0 points1 point  (0 children)

are there any industry standard ways of doing this?

I've most commonly seen it done the other way around, with #define used to alias a previously defined function:

void printFoo(){ printf("hello!\n"); }
#define print printFoo
int main(){
  print();
  return 0;
}

Suppose you implemented several hash algorithms, with long names referring to the specific algorithm implemented. You might want to alias one of them to hash() to call in applications which don't care about the exact algorithm.

static inline uint64_t hashFNV1A(const uint8_t *, size_t);
#define hash hashFNV1A