How to pass COMMA as an operator into macro. (Not the FAQ).

P

pedroalves

Hi all,

This is not a question about how to #define COMMA ,
Please keep reading.

Recently in binutils, we introduced a macro like this:

#define STRING_COMMA_LEN(STR) \
(STR), ((STR) ? sizeof (STR) - 1 : 0)

So in cases where we have a struct like this:

struct astruct
{
const char* str;
size_t len;
};

We can replace the manually inserted length:

struct astruct astruct_inst[] =
{ {"a string", 8} };

With:

struct astruct astruct_inst[] =
{ { STRING_COMMA_LEN("a string") } };

All good.

On with the question:

If you try to compile the code below, and strncmp happens to be a
macro,
the compiler will complain with an error, because the comma inserted
by STRING_COMMA_LEN will not be considered an operator by the time
strncmp is evaluated.

const char *a;
strncmp (a, STRING_COMMA_LEN("a string"));

Is there *any* way the STRING_COMMA_LEN could be changed
so this compiles, without touching the strncmp definition?

Or more generally, is there any way a macro can generate a comma
that will be considered an operator by the next macro?

Cheers,
Pedro Alves
 
P

Peter Nilsson

pedroalves said:
Recently in binutils, we introduced a macro like this:

#define STRING_COMMA_LEN(STR) \
(STR), ((STR) ? sizeof (STR) - 1 : 0)

Why use the conditional operator, you will get 0 for "" anyway?
So in cases where we have a struct like this:

struct astruct
{
const char* str;
size_t len;
};

We can replace the manually inserted length:

struct astruct astruct_inst[] =
{ {"a string", 8} };

With:

struct astruct astruct_inst[] =
{ { STRING_COMMA_LEN("a string") } };

All good.

On with the question:

If you try to compile the code below, and strncmp happens to be a
macro, the compiler will complain with an error, because the comma
inserted by STRING_COMMA_LEN will not be considered an operator
by the time strncmp is evaluated.

const char *a;
strncmp (a, STRING_COMMA_LEN("a string"));

Is there *any* way the STRING_COMMA_LEN could be changed
so this compiles, without touching the strncmp definition?

One way is to force a function call...

(strncmp)(a, STRING_COMMA_LEN("a string"));

But I think stylistically, it's better to scrap your macro and make the
code more obvious...

#define LITLEN(x) ((sizeof x) - 1)

static char a_string[] = "a string"; /* or #define, but somewhere
more
accessible that buried deep in the source code */

strncmp(a, a_string, LITLEN(a_string));
Or more generally, is there any way a macro can generate a comma
that will be considered an operator by the next macro?

Not in the way you want, AFAIK.

You can use an intermediate macro...

#define STRNCMPLIT(a,b) strncmp(a, b)

STRNCMPLIT(a, STRING_COMMA_LEN("a string"));

Or...

#define STRNCMPLIT2(a,b) \
APPLY(foo, a, STRING_COMMA_LEN(b))

#define APPLY(m, a, b) m(a, b)

STRNCMPLIT2(a, "a_string");

But the fact is... strncmp takes three arguments. All you're doing is
obfuscating
that. The situation is no different for the general case.
 
A

Ark

pedroalves said:
Hi all,

This is not a question about how to #define COMMA ,
Please keep reading.

Recently in binutils, we introduced a macro like this:

#define STRING_COMMA_LEN(STR) \
(STR), ((STR) ? sizeof (STR) - 1 : 0)

So in cases where we have a struct like this:

struct astruct
{
const char* str;
size_t len;
};

We can replace the manually inserted length:

struct astruct astruct_inst[] =
{ {"a string", 8} };

With:

struct astruct astruct_inst[] =
{ { STRING_COMMA_LEN("a string") } };

All good.

On with the question:

If you try to compile the code below, and strncmp happens to be a
macro,
the compiler will complain with an error, because the comma inserted
by STRING_COMMA_LEN will not be considered an operator by the time
strncmp is evaluated.

const char *a;
strncmp (a, STRING_COMMA_LEN("a string"));

Is there *any* way the STRING_COMMA_LEN could be changed
so this compiles, without touching the strncmp definition?

Or more generally, is there any way a macro can generate a comma
that will be considered an operator by the next macro?

Cheers,
Pedro Alves
If I remember correctly the macro expansion rules in this late hour, you
need to wrap the /target/ macro to achieve the result you want:
#define STRNCMP(str, combo) strncmp(str, combo)
- Ark
 
P

pedroalves

Peter said:
One way is to force a function call...

(strncmp)(a, STRING_COMMA_LEN("a string"));

Humm, I can't get this to compile.
#define my_strncmp(A, B, C)

#define STRING_COMMA_LEN(STR) \
(STR), ((STR) ? sizeof (STR) - 1 : 0)

int main()
{
const char* a;
(my_strncmp)(a, STRING_COMMA_LEN("a string"));
return 0;
}

main.c:9: error: `my_strncmp' undeclared (first use in this function)

I must be missing something.
But the fact is... strncmp takes three arguments. All you're doing is
obfuscating
that. The situation is no different for the general case.

Yes, I agree. This was just an example.
I wanted this to build new macros on top of existing ones.
Thanks all, this has been very enlightning.
 
P

Peter Nilsson

pedroalves said:
Humm, I can't get this to compile.
#define my_strncmp(A, B, C)

#define STRING_COMMA_LEN(STR) \
(STR), ((STR) ? sizeof (STR) - 1 : 0)

int main()
{
const char* a;
(my_strncmp)(a, STRING_COMMA_LEN("a string"));
return 0;
}

main.c:9: error: `my_strncmp' undeclared (first use in this function)

I must be missing something.

That's because you haven't declared a (non-macro) function called
my_strncmp.

If you're now telling me that your 'strncmp' example wasn't strncmp but
was
infact a different macro foo (say) that calls a function not called
foo, then
that changes things.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top