Implementing formatted print with the possibility to do nothing when it gets no arguments
I want to implement a macro named PRINT
which gets zero or more parameters, and does the following:
- If it gets zero parameters - do nothing.
- If it gets one or more arguments - act like printf.
I succeed in implementing it as you can see in my code below, but only at the cost of calling to printf with an empty string in the case we get zero arguments.
Is there a way I can handle the zero arguments case without calling to printf (it's not efficient to print something when you just want to do nothing)?
#include <stdio.h>
#define PRINT(...) printf("" __VA_ARGS__);
int main()
PRINT();
PRINT("printn");
PRINT("print number: %dn", 7);
return 0;
output:
print
print number: 7
c macros printf variadic-functions
add a comment |
I want to implement a macro named PRINT
which gets zero or more parameters, and does the following:
- If it gets zero parameters - do nothing.
- If it gets one or more arguments - act like printf.
I succeed in implementing it as you can see in my code below, but only at the cost of calling to printf with an empty string in the case we get zero arguments.
Is there a way I can handle the zero arguments case without calling to printf (it's not efficient to print something when you just want to do nothing)?
#include <stdio.h>
#define PRINT(...) printf("" __VA_ARGS__);
int main()
PRINT();
PRINT("printn");
PRINT("print number: %dn", 7);
return 0;
output:
print
print number: 7
c macros printf variadic-functions
2
Where does the emptyPRINT()
come from? From another macro? (Any human programmer could probably just delete it.)
– M Oehm
Nov 14 '18 at 10:37
Jens Gustedt answered a question on detecting an empty argument list and showed how. It is quite involved.
– Eric Postpischil
Nov 15 '18 at 0:24
add a comment |
I want to implement a macro named PRINT
which gets zero or more parameters, and does the following:
- If it gets zero parameters - do nothing.
- If it gets one or more arguments - act like printf.
I succeed in implementing it as you can see in my code below, but only at the cost of calling to printf with an empty string in the case we get zero arguments.
Is there a way I can handle the zero arguments case without calling to printf (it's not efficient to print something when you just want to do nothing)?
#include <stdio.h>
#define PRINT(...) printf("" __VA_ARGS__);
int main()
PRINT();
PRINT("printn");
PRINT("print number: %dn", 7);
return 0;
output:
print
print number: 7
c macros printf variadic-functions
I want to implement a macro named PRINT
which gets zero or more parameters, and does the following:
- If it gets zero parameters - do nothing.
- If it gets one or more arguments - act like printf.
I succeed in implementing it as you can see in my code below, but only at the cost of calling to printf with an empty string in the case we get zero arguments.
Is there a way I can handle the zero arguments case without calling to printf (it's not efficient to print something when you just want to do nothing)?
#include <stdio.h>
#define PRINT(...) printf("" __VA_ARGS__);
int main()
PRINT();
PRINT("printn");
PRINT("print number: %dn", 7);
return 0;
output:
print
print number: 7
c macros printf variadic-functions
c macros printf variadic-functions
edited Nov 14 '18 at 10:32
Jabberwocky
27.1k93772
27.1k93772
asked Nov 14 '18 at 10:12
RodrigoRodrigo
627
627
2
Where does the emptyPRINT()
come from? From another macro? (Any human programmer could probably just delete it.)
– M Oehm
Nov 14 '18 at 10:37
Jens Gustedt answered a question on detecting an empty argument list and showed how. It is quite involved.
– Eric Postpischil
Nov 15 '18 at 0:24
add a comment |
2
Where does the emptyPRINT()
come from? From another macro? (Any human programmer could probably just delete it.)
– M Oehm
Nov 14 '18 at 10:37
Jens Gustedt answered a question on detecting an empty argument list and showed how. It is quite involved.
– Eric Postpischil
Nov 15 '18 at 0:24
2
2
Where does the empty
PRINT()
come from? From another macro? (Any human programmer could probably just delete it.)– M Oehm
Nov 14 '18 at 10:37
Where does the empty
PRINT()
come from? From another macro? (Any human programmer could probably just delete it.)– M Oehm
Nov 14 '18 at 10:37
Jens Gustedt answered a question on detecting an empty argument list and showed how. It is quite involved.
– Eric Postpischil
Nov 15 '18 at 0:24
Jens Gustedt answered a question on detecting an empty argument list and showed how. It is quite involved.
– Eric Postpischil
Nov 15 '18 at 0:24
add a comment |
3 Answers
3
active
oldest
votes
Both gcc and clang will completely eliminate the call to printf
in the case that it is passed an empty format string. Probably that optimisation is reasonably common.
See here and here for disassembly on gcc.godbolt.org.
In short, don't worry about it.
add a comment |
A solution is:
#define Argument1(a,...) Argument2(a
#define Argument2(a, b,...) b
#define TestEmpty() ,
#define PRINT(...) Argument1(TestEmpty __VA_ARGS__ (),), printf(__VA_ARGS__);,)
For this source text:
Test 0: PRINT()
Test 1: PRINT("Hello, world.n")
Test 2: PRINT("Result is %d.n", result)
Test 3: PRINT("%d = %g.n", 3, 3.)
the result of preprocessing is:
Test 0:
Test 1: printf("Hello, world.n");
Test 2: printf("Result is %d.n", result);
Test 3: printf("%d = %g.n", 3, 3.);
This requires that the arguments to PRINT
not start with a parenthesized item, which seems acceptable for this particular question. The code here is not a general solution for detecting an empty parameter when parentheses may be present.
Explanation:
- In preparing to replace
PRINT
,__VA_ARGS__
is replaced.TestEmpty
is not replaced at this time because it is not followed by parentheses. - Then
PRINT
is replaced, and the result is rescanned. Argument1
is identified for replacement. In preparation for that, its arguments are processed.- At this point, if
__VA_ARGS__
is empty, we have have the tokensTestEmpty ()
, which are replaced by,
. Otherwise,TestEmpty <some tokens> ()
remains. Note that, ifTestEmpty ()
is present, the,
it expands to is the first argument toArgument1
. It is not an argument separator, because the arguments toArgument1
have already been identified. - Then
Argument1
is replaced, producing eitherArgument2(,
(if__VA_ARGS
was empty) orArgument2(TestEmpty
possibly followed by additional tokens (otherwise). - The result is either
Argument2(,, printf();,)
orArgument2(TestEmpty <some tokens>, printf(<some tokens>);,)
, according to whether__VA_ARGS__
was empty or not. - The tokens are now rescanned for further replacement, so the
,
will now be recognized as an argument separator. - Finally,
Argument2
is replaced with an empty token list or withprintf(<some tokens>);
.
Brilliant use of the preprocessor. But what about Test 4?char *str = "This is a string.n"; PRINT(str);
Or Test 5?char *str = ""; PRINT(str);
I'd also be very concerned about maintainability and loathe to release those macros in the wilds of some large project.
– Andrew Henle
Nov 15 '18 at 12:46
@AndrewHenle: Your proposed tests 4 and 5 result inprintf(str);
, as desired. As long as the first argument does not start with a parentheses, I think the macros will work. If they start with any non-empty parentheses, an error should be generated, so the problem will be caught. It is rare forprintf
arguments to start with parentheses. I suspect the most likely case would be something likePRINT(SomeMacroToPrepareFormatString(stuff),…)
, where the macro expands to a parenthesized sequence (out of the common habit of parenthesizing macro replacement text, not necessary in this case…
– Eric Postpischil
Nov 15 '18 at 13:49
@AndrewHenle: … unless the replacement text contains a comma operator that needs to be parenthesized to prevent it from being interpreted as an argument separator). I would not recommend this for a large project; I am just answering the Stack Overflow question because knowledge is valuable.
– Eric Postpischil
Nov 15 '18 at 13:50
add a comment |
If you do want to outsource the check of empty argument list to the macro, then perhaps something like this:
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
This relies on the compound literal getting size 1 in case of an empty string = null terminator only. Example:
#include <stdio.h>
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
int main (void)
int i = 5;
PRINT("%dn", i);
PRINT();
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53297695%2fimplementing-formatted-print-with-the-possibility-to-do-nothing-when-it-gets-no%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Both gcc and clang will completely eliminate the call to printf
in the case that it is passed an empty format string. Probably that optimisation is reasonably common.
See here and here for disassembly on gcc.godbolt.org.
In short, don't worry about it.
add a comment |
Both gcc and clang will completely eliminate the call to printf
in the case that it is passed an empty format string. Probably that optimisation is reasonably common.
See here and here for disassembly on gcc.godbolt.org.
In short, don't worry about it.
add a comment |
Both gcc and clang will completely eliminate the call to printf
in the case that it is passed an empty format string. Probably that optimisation is reasonably common.
See here and here for disassembly on gcc.godbolt.org.
In short, don't worry about it.
Both gcc and clang will completely eliminate the call to printf
in the case that it is passed an empty format string. Probably that optimisation is reasonably common.
See here and here for disassembly on gcc.godbolt.org.
In short, don't worry about it.
answered Nov 14 '18 at 14:31
ricirici
154k19135202
154k19135202
add a comment |
add a comment |
A solution is:
#define Argument1(a,...) Argument2(a
#define Argument2(a, b,...) b
#define TestEmpty() ,
#define PRINT(...) Argument1(TestEmpty __VA_ARGS__ (),), printf(__VA_ARGS__);,)
For this source text:
Test 0: PRINT()
Test 1: PRINT("Hello, world.n")
Test 2: PRINT("Result is %d.n", result)
Test 3: PRINT("%d = %g.n", 3, 3.)
the result of preprocessing is:
Test 0:
Test 1: printf("Hello, world.n");
Test 2: printf("Result is %d.n", result);
Test 3: printf("%d = %g.n", 3, 3.);
This requires that the arguments to PRINT
not start with a parenthesized item, which seems acceptable for this particular question. The code here is not a general solution for detecting an empty parameter when parentheses may be present.
Explanation:
- In preparing to replace
PRINT
,__VA_ARGS__
is replaced.TestEmpty
is not replaced at this time because it is not followed by parentheses. - Then
PRINT
is replaced, and the result is rescanned. Argument1
is identified for replacement. In preparation for that, its arguments are processed.- At this point, if
__VA_ARGS__
is empty, we have have the tokensTestEmpty ()
, which are replaced by,
. Otherwise,TestEmpty <some tokens> ()
remains. Note that, ifTestEmpty ()
is present, the,
it expands to is the first argument toArgument1
. It is not an argument separator, because the arguments toArgument1
have already been identified. - Then
Argument1
is replaced, producing eitherArgument2(,
(if__VA_ARGS
was empty) orArgument2(TestEmpty
possibly followed by additional tokens (otherwise). - The result is either
Argument2(,, printf();,)
orArgument2(TestEmpty <some tokens>, printf(<some tokens>);,)
, according to whether__VA_ARGS__
was empty or not. - The tokens are now rescanned for further replacement, so the
,
will now be recognized as an argument separator. - Finally,
Argument2
is replaced with an empty token list or withprintf(<some tokens>);
.
Brilliant use of the preprocessor. But what about Test 4?char *str = "This is a string.n"; PRINT(str);
Or Test 5?char *str = ""; PRINT(str);
I'd also be very concerned about maintainability and loathe to release those macros in the wilds of some large project.
– Andrew Henle
Nov 15 '18 at 12:46
@AndrewHenle: Your proposed tests 4 and 5 result inprintf(str);
, as desired. As long as the first argument does not start with a parentheses, I think the macros will work. If they start with any non-empty parentheses, an error should be generated, so the problem will be caught. It is rare forprintf
arguments to start with parentheses. I suspect the most likely case would be something likePRINT(SomeMacroToPrepareFormatString(stuff),…)
, where the macro expands to a parenthesized sequence (out of the common habit of parenthesizing macro replacement text, not necessary in this case…
– Eric Postpischil
Nov 15 '18 at 13:49
@AndrewHenle: … unless the replacement text contains a comma operator that needs to be parenthesized to prevent it from being interpreted as an argument separator). I would not recommend this for a large project; I am just answering the Stack Overflow question because knowledge is valuable.
– Eric Postpischil
Nov 15 '18 at 13:50
add a comment |
A solution is:
#define Argument1(a,...) Argument2(a
#define Argument2(a, b,...) b
#define TestEmpty() ,
#define PRINT(...) Argument1(TestEmpty __VA_ARGS__ (),), printf(__VA_ARGS__);,)
For this source text:
Test 0: PRINT()
Test 1: PRINT("Hello, world.n")
Test 2: PRINT("Result is %d.n", result)
Test 3: PRINT("%d = %g.n", 3, 3.)
the result of preprocessing is:
Test 0:
Test 1: printf("Hello, world.n");
Test 2: printf("Result is %d.n", result);
Test 3: printf("%d = %g.n", 3, 3.);
This requires that the arguments to PRINT
not start with a parenthesized item, which seems acceptable for this particular question. The code here is not a general solution for detecting an empty parameter when parentheses may be present.
Explanation:
- In preparing to replace
PRINT
,__VA_ARGS__
is replaced.TestEmpty
is not replaced at this time because it is not followed by parentheses. - Then
PRINT
is replaced, and the result is rescanned. Argument1
is identified for replacement. In preparation for that, its arguments are processed.- At this point, if
__VA_ARGS__
is empty, we have have the tokensTestEmpty ()
, which are replaced by,
. Otherwise,TestEmpty <some tokens> ()
remains. Note that, ifTestEmpty ()
is present, the,
it expands to is the first argument toArgument1
. It is not an argument separator, because the arguments toArgument1
have already been identified. - Then
Argument1
is replaced, producing eitherArgument2(,
(if__VA_ARGS
was empty) orArgument2(TestEmpty
possibly followed by additional tokens (otherwise). - The result is either
Argument2(,, printf();,)
orArgument2(TestEmpty <some tokens>, printf(<some tokens>);,)
, according to whether__VA_ARGS__
was empty or not. - The tokens are now rescanned for further replacement, so the
,
will now be recognized as an argument separator. - Finally,
Argument2
is replaced with an empty token list or withprintf(<some tokens>);
.
Brilliant use of the preprocessor. But what about Test 4?char *str = "This is a string.n"; PRINT(str);
Or Test 5?char *str = ""; PRINT(str);
I'd also be very concerned about maintainability and loathe to release those macros in the wilds of some large project.
– Andrew Henle
Nov 15 '18 at 12:46
@AndrewHenle: Your proposed tests 4 and 5 result inprintf(str);
, as desired. As long as the first argument does not start with a parentheses, I think the macros will work. If they start with any non-empty parentheses, an error should be generated, so the problem will be caught. It is rare forprintf
arguments to start with parentheses. I suspect the most likely case would be something likePRINT(SomeMacroToPrepareFormatString(stuff),…)
, where the macro expands to a parenthesized sequence (out of the common habit of parenthesizing macro replacement text, not necessary in this case…
– Eric Postpischil
Nov 15 '18 at 13:49
@AndrewHenle: … unless the replacement text contains a comma operator that needs to be parenthesized to prevent it from being interpreted as an argument separator). I would not recommend this for a large project; I am just answering the Stack Overflow question because knowledge is valuable.
– Eric Postpischil
Nov 15 '18 at 13:50
add a comment |
A solution is:
#define Argument1(a,...) Argument2(a
#define Argument2(a, b,...) b
#define TestEmpty() ,
#define PRINT(...) Argument1(TestEmpty __VA_ARGS__ (),), printf(__VA_ARGS__);,)
For this source text:
Test 0: PRINT()
Test 1: PRINT("Hello, world.n")
Test 2: PRINT("Result is %d.n", result)
Test 3: PRINT("%d = %g.n", 3, 3.)
the result of preprocessing is:
Test 0:
Test 1: printf("Hello, world.n");
Test 2: printf("Result is %d.n", result);
Test 3: printf("%d = %g.n", 3, 3.);
This requires that the arguments to PRINT
not start with a parenthesized item, which seems acceptable for this particular question. The code here is not a general solution for detecting an empty parameter when parentheses may be present.
Explanation:
- In preparing to replace
PRINT
,__VA_ARGS__
is replaced.TestEmpty
is not replaced at this time because it is not followed by parentheses. - Then
PRINT
is replaced, and the result is rescanned. Argument1
is identified for replacement. In preparation for that, its arguments are processed.- At this point, if
__VA_ARGS__
is empty, we have have the tokensTestEmpty ()
, which are replaced by,
. Otherwise,TestEmpty <some tokens> ()
remains. Note that, ifTestEmpty ()
is present, the,
it expands to is the first argument toArgument1
. It is not an argument separator, because the arguments toArgument1
have already been identified. - Then
Argument1
is replaced, producing eitherArgument2(,
(if__VA_ARGS
was empty) orArgument2(TestEmpty
possibly followed by additional tokens (otherwise). - The result is either
Argument2(,, printf();,)
orArgument2(TestEmpty <some tokens>, printf(<some tokens>);,)
, according to whether__VA_ARGS__
was empty or not. - The tokens are now rescanned for further replacement, so the
,
will now be recognized as an argument separator. - Finally,
Argument2
is replaced with an empty token list or withprintf(<some tokens>);
.
A solution is:
#define Argument1(a,...) Argument2(a
#define Argument2(a, b,...) b
#define TestEmpty() ,
#define PRINT(...) Argument1(TestEmpty __VA_ARGS__ (),), printf(__VA_ARGS__);,)
For this source text:
Test 0: PRINT()
Test 1: PRINT("Hello, world.n")
Test 2: PRINT("Result is %d.n", result)
Test 3: PRINT("%d = %g.n", 3, 3.)
the result of preprocessing is:
Test 0:
Test 1: printf("Hello, world.n");
Test 2: printf("Result is %d.n", result);
Test 3: printf("%d = %g.n", 3, 3.);
This requires that the arguments to PRINT
not start with a parenthesized item, which seems acceptable for this particular question. The code here is not a general solution for detecting an empty parameter when parentheses may be present.
Explanation:
- In preparing to replace
PRINT
,__VA_ARGS__
is replaced.TestEmpty
is not replaced at this time because it is not followed by parentheses. - Then
PRINT
is replaced, and the result is rescanned. Argument1
is identified for replacement. In preparation for that, its arguments are processed.- At this point, if
__VA_ARGS__
is empty, we have have the tokensTestEmpty ()
, which are replaced by,
. Otherwise,TestEmpty <some tokens> ()
remains. Note that, ifTestEmpty ()
is present, the,
it expands to is the first argument toArgument1
. It is not an argument separator, because the arguments toArgument1
have already been identified. - Then
Argument1
is replaced, producing eitherArgument2(,
(if__VA_ARGS
was empty) orArgument2(TestEmpty
possibly followed by additional tokens (otherwise). - The result is either
Argument2(,, printf();,)
orArgument2(TestEmpty <some tokens>, printf(<some tokens>);,)
, according to whether__VA_ARGS__
was empty or not. - The tokens are now rescanned for further replacement, so the
,
will now be recognized as an argument separator. - Finally,
Argument2
is replaced with an empty token list or withprintf(<some tokens>);
.
edited Nov 15 '18 at 18:17
answered Nov 15 '18 at 3:35
Eric PostpischilEric Postpischil
75.4k880162
75.4k880162
Brilliant use of the preprocessor. But what about Test 4?char *str = "This is a string.n"; PRINT(str);
Or Test 5?char *str = ""; PRINT(str);
I'd also be very concerned about maintainability and loathe to release those macros in the wilds of some large project.
– Andrew Henle
Nov 15 '18 at 12:46
@AndrewHenle: Your proposed tests 4 and 5 result inprintf(str);
, as desired. As long as the first argument does not start with a parentheses, I think the macros will work. If they start with any non-empty parentheses, an error should be generated, so the problem will be caught. It is rare forprintf
arguments to start with parentheses. I suspect the most likely case would be something likePRINT(SomeMacroToPrepareFormatString(stuff),…)
, where the macro expands to a parenthesized sequence (out of the common habit of parenthesizing macro replacement text, not necessary in this case…
– Eric Postpischil
Nov 15 '18 at 13:49
@AndrewHenle: … unless the replacement text contains a comma operator that needs to be parenthesized to prevent it from being interpreted as an argument separator). I would not recommend this for a large project; I am just answering the Stack Overflow question because knowledge is valuable.
– Eric Postpischil
Nov 15 '18 at 13:50
add a comment |
Brilliant use of the preprocessor. But what about Test 4?char *str = "This is a string.n"; PRINT(str);
Or Test 5?char *str = ""; PRINT(str);
I'd also be very concerned about maintainability and loathe to release those macros in the wilds of some large project.
– Andrew Henle
Nov 15 '18 at 12:46
@AndrewHenle: Your proposed tests 4 and 5 result inprintf(str);
, as desired. As long as the first argument does not start with a parentheses, I think the macros will work. If they start with any non-empty parentheses, an error should be generated, so the problem will be caught. It is rare forprintf
arguments to start with parentheses. I suspect the most likely case would be something likePRINT(SomeMacroToPrepareFormatString(stuff),…)
, where the macro expands to a parenthesized sequence (out of the common habit of parenthesizing macro replacement text, not necessary in this case…
– Eric Postpischil
Nov 15 '18 at 13:49
@AndrewHenle: … unless the replacement text contains a comma operator that needs to be parenthesized to prevent it from being interpreted as an argument separator). I would not recommend this for a large project; I am just answering the Stack Overflow question because knowledge is valuable.
– Eric Postpischil
Nov 15 '18 at 13:50
Brilliant use of the preprocessor. But what about Test 4?
char *str = "This is a string.n"; PRINT(str);
Or Test 5? char *str = ""; PRINT(str);
I'd also be very concerned about maintainability and loathe to release those macros in the wilds of some large project.– Andrew Henle
Nov 15 '18 at 12:46
Brilliant use of the preprocessor. But what about Test 4?
char *str = "This is a string.n"; PRINT(str);
Or Test 5? char *str = ""; PRINT(str);
I'd also be very concerned about maintainability and loathe to release those macros in the wilds of some large project.– Andrew Henle
Nov 15 '18 at 12:46
@AndrewHenle: Your proposed tests 4 and 5 result in
printf(str);
, as desired. As long as the first argument does not start with a parentheses, I think the macros will work. If they start with any non-empty parentheses, an error should be generated, so the problem will be caught. It is rare for printf
arguments to start with parentheses. I suspect the most likely case would be something like PRINT(SomeMacroToPrepareFormatString(stuff),…)
, where the macro expands to a parenthesized sequence (out of the common habit of parenthesizing macro replacement text, not necessary in this case…– Eric Postpischil
Nov 15 '18 at 13:49
@AndrewHenle: Your proposed tests 4 and 5 result in
printf(str);
, as desired. As long as the first argument does not start with a parentheses, I think the macros will work. If they start with any non-empty parentheses, an error should be generated, so the problem will be caught. It is rare for printf
arguments to start with parentheses. I suspect the most likely case would be something like PRINT(SomeMacroToPrepareFormatString(stuff),…)
, where the macro expands to a parenthesized sequence (out of the common habit of parenthesizing macro replacement text, not necessary in this case…– Eric Postpischil
Nov 15 '18 at 13:49
@AndrewHenle: … unless the replacement text contains a comma operator that needs to be parenthesized to prevent it from being interpreted as an argument separator). I would not recommend this for a large project; I am just answering the Stack Overflow question because knowledge is valuable.
– Eric Postpischil
Nov 15 '18 at 13:50
@AndrewHenle: … unless the replacement text contains a comma operator that needs to be parenthesized to prevent it from being interpreted as an argument separator). I would not recommend this for a large project; I am just answering the Stack Overflow question because knowledge is valuable.
– Eric Postpischil
Nov 15 '18 at 13:50
add a comment |
If you do want to outsource the check of empty argument list to the macro, then perhaps something like this:
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
This relies on the compound literal getting size 1 in case of an empty string = null terminator only. Example:
#include <stdio.h>
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
int main (void)
int i = 5;
PRINT("%dn", i);
PRINT();
add a comment |
If you do want to outsource the check of empty argument list to the macro, then perhaps something like this:
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
This relies on the compound literal getting size 1 in case of an empty string = null terminator only. Example:
#include <stdio.h>
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
int main (void)
int i = 5;
PRINT("%dn", i);
PRINT();
add a comment |
If you do want to outsource the check of empty argument list to the macro, then perhaps something like this:
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
This relies on the compound literal getting size 1 in case of an empty string = null terminator only. Example:
#include <stdio.h>
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
int main (void)
int i = 5;
PRINT("%dn", i);
PRINT();
If you do want to outsource the check of empty argument list to the macro, then perhaps something like this:
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
This relies on the compound literal getting size 1 in case of an empty string = null terminator only. Example:
#include <stdio.h>
#define HAS_ARGS(...) (sizeof( (char)#__VA_ARGS__ ) > 1)
#define PRINT(...) (HAS_ARGS(__VA_ARGS__) ? printf("" __VA_ARGS__) : (void)0)
int main (void)
int i = 5;
PRINT("%dn", i);
PRINT();
answered Nov 14 '18 at 14:45
LundinLundin
109k17160265
109k17160265
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53297695%2fimplementing-formatted-print-with-the-possibility-to-do-nothing-when-it-gets-no%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Where does the empty
PRINT()
come from? From another macro? (Any human programmer could probably just delete it.)– M Oehm
Nov 14 '18 at 10:37
Jens Gustedt answered a question on detecting an empty argument list and showed how. It is quite involved.
– Eric Postpischil
Nov 15 '18 at 0:24