Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Default values in #define

57 views
Skip to first unread message

Rick C. Hodgin

unread,
Aug 19, 2016, 5:55:56 PM8/19/16
to
I tried to do this today, and the compiler balked. Is there a syntax
where this idea is legal (line 06 and the [c = "hello"] part)?

01: void myfunc(int value, char* text)
02: {
03: printf("%d %s\n", value, text);
04: }
05:
06: #define abc(a, b, c = "hello") a(b, c)
07:
08: abc(myfunc, 2);

Best regards,
Rick C. Hodgin

Mr Flibble

unread,
Aug 19, 2016, 5:57:10 PM8/19/16
to
Don't use macros.

/Flibble

bitrex

unread,
Aug 19, 2016, 6:11:18 PM8/19/16
to

red floyd

unread,
Aug 19, 2016, 9:40:22 PM8/19/16
to
Since neither response so far has addressed your question,

No. There is no such thing as default arguments for macros.


Ian Collins

unread,
Aug 19, 2016, 10:50:59 PM8/19/16
to
On 08/20/16 02:10 PM, Rick C. Hodgin wrote:
> On Friday, August 19, 2016 at 9:15:59 PM UTC-4, Ian Collins wrote:
>> On 08/20/16 01:09 PM, Rick C. Hodgin wrote:
>>> On Friday, August 19, 2016 at 6:14:30 PM UTC-4, Ian Collins wrote:
>>>> On 08/20/16 09:56 AM, BartC wrote:
>>>>> On 19/08/2016 22:36, Ian Collins wrote:
>>>>>> On 08/20/16 09:22 AM, Rick C. Hodgin wrote:
>>>>>>> I tried to do this today, and the compiler balked. Is there a syntax
>>>>>>> where this idea is legal (line 06 and the [c = "hello"] part)?
>>>>>>>
>>>>>>> 01: void myfunc(int value, char* text)
>>>>>>> 02: {
>>>>>>> 03: printf("%d %s\n", value, text);
>>>>>>> 04: }
>>>>>>> 05:
>>>>>>> 06: #define abc(a, b, c = "hello") a(b, c)
>>>>>>> 07:
>>>>>>> 08: abc(myfunc, 2);
>>>>>>
>>>>>> If you want C++, you know where to find it!
>>>>>
>>>>> I tried it in C++ and it didn't seem to work.
>>>>
>>>> In C++, we don't use macros.
>>>>
>>>> A function template like
>>>>
>>>> template <typename Fn, typename B>
>>>> void abc( Fn a, B b, const char* c = "hello") { a(b, c); }
>>>>
>>>> would be used.
>>>
>>> 01: void myfunc(int value, char* text)
>>> 02: {
>>> 03: printf("%d %s\n", value, text);
>>> 04: }
>>> 05:
>>> 06: #define abc(a, b, c = "no param given") a(b, c)
>>> 07:
>>> 08: abc(myfunc, 2);
>>> 09: abc(myfunc, 5, "five");
>>
>> # cat x.cc
>> #include <stdio.h>
>>
>> void myfunc(int value, const char* text)
>> {
>> printf("%d %s\n", value, text);
>> }
>>
>> template <typename Fn, typename B>
>> void abc( Fn a, B b, const char* c = "no param given" ) { a(b, c); }
>>
>> int main()
>> {
>> abc(myfunc, 2);
>> abc(myfunc, 5, "five");
>> }
>>
>> # CC x.cc; ./a.out;
>> 2 no param given
>> 5 five
>
> I appreciate your response, Ian. There are things about this I don't
> understand, but since it's clc, I'll let it go.

Seeing as you also asked there, I've cross-posted to c.l.c++ so you can
follow up there.

--
Ian

Rick C. Hodgin

unread,
Aug 19, 2016, 10:59:26 PM8/19/16
to
I don't expect a tutorial on C++, but the things I don't understand are as
follows:

01: template <typename Fn, typename B>
02: void abc( Fn a, B b, const char* c = "no param given" ) { a(b, c); }

typename Fn
typename B

Why "typename"? Why "Fn"? And why "B"? Could other symbols have been used,
or are those explicit in C++ (such that "Fn" means function)?

What's the purpose of the { and } here? Are they defining the template? And
is the template in this small case being only the translation? Would this
code expand out to essentially perform what a #define would do, modifying the
original source code:

abc(myfunc, 2);
abc(myfunc, 5, "five");

To then product translated source code through the template:

myfunc(2, "no param given");
myfunc(5, "five");

?

At least it seems to be that way from looking at the generated assembly
source code.

Ian Collins

unread,
Aug 19, 2016, 11:11:58 PM8/19/16
to
On 08/20/16 02:59 PM, Rick C. Hodgin wrote:
> On Friday, August 19, 2016 at 10:50:59 PM UTC-4, Ian Collins wrote:
>> On 08/20/16 02:10 PM, Rick C. Hodgin wrote:
>>> On Friday, August 19, 2016 at 9:15:59 PM UTC-4, Ian Collins wrote:
>>>>
>>>> # cat x.cc
>>>> #include <stdio.h>
>>>>
>>>> void myfunc(int value, const char* text)
>>>> {
>>>> printf("%d %s\n", value, text);
>>>> }
>>>>
>>>> template <typename Fn, typename B>
>>>> void abc( Fn a, B b, const char* c = "no param given" ) { a(b, c); }
>>>>
>>>> int main()
>>>> {
>>>> abc(myfunc, 2);
>>>> abc(myfunc, 5, "five");
>>>> }
>>>>
>>>> # CC x.cc; ./a.out;
>>>> 2 no param given
>>>> 5 five
>
> I don't expect a tutorial on C++, but the things I don't understand are as
> follows:
>
> 01: template <typename Fn, typename B>
> 02: void abc( Fn a, B b, const char* c = "no param given" ) { a(b, c); }
>
> typename Fn
> typename B
>
> Why "typename"? Why "Fn"? And why "B"? Could other symbols have been used,
> or are those explicit in C++ (such that "Fn" means function)?

They are simply template arguments. Any name could have been used, just
like function parameters.

> What's the purpose of the { and } here? Are they defining the template?

abc is a function template, the stuff between the braces is the function
body, just like a normal function.

> And
> is the template in this small case being only the translation? Would this
> code expand out to essentially perform what a #define would do, modifying the
> original source code:
>
> abc(myfunc, 2);
> abc(myfunc, 5, "five");
>
> To then product translated source code through the template:
>
> myfunc(2, "no param given");
> myfunc(5, "five");
>
> ?
>
> At least it seems to be that way from looking at the generated assembly
> source code.

Pretty much, yes - assuming the function was inlined.

It would have generated a function with the signature

void abc( void (*a)( int,const char*), int b, const char* c);

--
Ian

Kalle Olavi Niemitalo

unread,
Aug 20, 2016, 3:32:59 AM8/20/16
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> 01: template <typename Fn, typename B>
> 02: void abc( Fn a, B b, const char* c = "no param given" ) { a(b, c); }
>
> typename Fn
> typename B
>
> Why "typename"?

"typename" is a reserved word that here means that the "Fn" and
"B" arguments of the template are types (rather than templates,
constant values, or addresses of objects). "class" would also
mean the same thing here, i.e. you could write "template <class
Fn, class B>", but it might be a bit misleading because the types
do not have to be class types.

Alf P. Steinbach

unread,
Aug 20, 2016, 8:40:12 AM8/20/16
to
Well technically he could use a variadic macro.


Cheers!,

- Alf


David Brown

unread,
Aug 20, 2016, 12:41:06 PM8/20/16
to
And the choices of "Fn" and "B" are arbitrary as far as the compiler is
concerned, but idiomatic for such templates, and therefore easier for
the programmer to understand. The typename arguments in a template are
types, yet logically they are also much like arguments in a function.
So just as you might use "a" and "b" as function arguments, you use "A"
and "B" as template type arguments. To keep things clear, it is useful
to use "A" as the type for function argument "a", "B" as the template
argument for function argument "b", and so on. And "Fn" is a good
choice of name for a function type.

You could also have written:

template <typename FuncParamType, typename FirstParamType>
void abc(FuncParamType func, FirstParamType param1,
const char* param2 = "no param given")
{
func(param1, param2);
}

It's the same thing - it's up to you which you find clearer.

m.laba...@gmail.com

unread,
Aug 22, 2016, 2:30:29 AM8/22/16
to
> https://gcc.gnu.org/onlinedocs/cpp/Stringification.html

'WARN_IF' macro from above link is buggy, example:
{
int x = 0;
int s = 7;
WARN_IF ((x%s) == 0); /* it makes fprintf(stderr, "Warning: (x%s) == 0\n") */
/* where %s is a special marker for printf */
}

Better is to use 'fputs':

#define WARN_IF(EXP) \
do { if (EXP) \
fputs ("Warning: " #EXP "\n", stderr); } \
while (0)

David Brown

unread,
Aug 22, 2016, 2:49:36 AM8/22/16
to
On 22/08/16 08:30, m.laba...@gmail.com wrote:
>> https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
>
> 'WARN_IF' macro from above link is buggy, example:
> {
> int x = 0;
> int s = 7;
> WARN_IF ((x%s) == 0); /* it makes fprintf(stderr, "Warning: (x%s) == 0\n") */
> /* where %s is a special marker for printf */
> }

The problem could be avoided here if you used sensible spacing around
the % operator. But the principle is right.

>
> Better is to use 'fputs':
>
> #define WARN_IF(EXP) \
> do { if (EXP) \
> fputs ("Warning: " #EXP "\n", stderr); } \
> while (0)
>

That sounds reasonable. You can do even better, however:

extern void __attribute__((error("WARN_IF always triggered")))
warnIfAlwaysTriggered(void);

#define WARN_IF(EXP) \
do { \
if (__builtin_constant_p(EXP)) { \
if (EXP) { \
warnIfAlwaysTriggered(); \
} \
} \
if (EXP) { \
fputs ("Warning: " #EXP "\n", stderr); \
} \
} while (0)


Then you get a compile-time error as well, if the compiler can see that
the warning is always going to be triggered - as that will almost
certainly mean a program bug.

__builtin_constant_p and the error __attribute__ are, of course,
gcc-isms, but the reference was to a page in the gcc manual about
stringification.

0 new messages