Workaround for “semicolon in global scope” warning for no-op C macro

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












12














In a codebase that can be built as either C or C++, I thought I'd make a macro to take advantage of static_assert in the case it's built as C++11 or higher.



(Note: I know there are ways to do this in pre-C11 C, at least if you're willing to take a message parameter--though it won't work quite everywhere. But for the sake of argument let's say I have some legitimate need to make it take no message, and be a no-op in at least some C builds.)



So here was the simple definition I tried:



#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond)
#endif


There's no semicolon in the macro, with the intent that you would add it at the callsite. But under pedantic C warning settings, this macro appearing in global scope causes:




error: ISO C does not allow extra ‘;’ outside of a function [-Werror=pedantic]




The easy solution seems to be to take the semicolon off the callsites, and put it in the C++11 side of the macro. But I wonder: how do you make a no-op macro in global scope which allows a semicolon at the callsite (without running afoul of some other warning)?










share|improve this question



















  • 3




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    Dec 25 '18 at 16:29










  • @RaymondChen It seems in some compiler/warning combinations you get warnings about having forward function declarations more than once. You can disable those, but assuming they are there for a good reason...the struct solution below doesn't appear to trigger any warnings.
    – HostileFork
    Dec 25 '18 at 16:42
















12














In a codebase that can be built as either C or C++, I thought I'd make a macro to take advantage of static_assert in the case it's built as C++11 or higher.



(Note: I know there are ways to do this in pre-C11 C, at least if you're willing to take a message parameter--though it won't work quite everywhere. But for the sake of argument let's say I have some legitimate need to make it take no message, and be a no-op in at least some C builds.)



So here was the simple definition I tried:



#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond)
#endif


There's no semicolon in the macro, with the intent that you would add it at the callsite. But under pedantic C warning settings, this macro appearing in global scope causes:




error: ISO C does not allow extra ‘;’ outside of a function [-Werror=pedantic]




The easy solution seems to be to take the semicolon off the callsites, and put it in the C++11 side of the macro. But I wonder: how do you make a no-op macro in global scope which allows a semicolon at the callsite (without running afoul of some other warning)?










share|improve this question



















  • 3




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    Dec 25 '18 at 16:29










  • @RaymondChen It seems in some compiler/warning combinations you get warnings about having forward function declarations more than once. You can disable those, but assuming they are there for a good reason...the struct solution below doesn't appear to trigger any warnings.
    – HostileFork
    Dec 25 '18 at 16:42














12












12








12


3





In a codebase that can be built as either C or C++, I thought I'd make a macro to take advantage of static_assert in the case it's built as C++11 or higher.



(Note: I know there are ways to do this in pre-C11 C, at least if you're willing to take a message parameter--though it won't work quite everywhere. But for the sake of argument let's say I have some legitimate need to make it take no message, and be a no-op in at least some C builds.)



So here was the simple definition I tried:



#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond)
#endif


There's no semicolon in the macro, with the intent that you would add it at the callsite. But under pedantic C warning settings, this macro appearing in global scope causes:




error: ISO C does not allow extra ‘;’ outside of a function [-Werror=pedantic]




The easy solution seems to be to take the semicolon off the callsites, and put it in the C++11 side of the macro. But I wonder: how do you make a no-op macro in global scope which allows a semicolon at the callsite (without running afoul of some other warning)?










share|improve this question















In a codebase that can be built as either C or C++, I thought I'd make a macro to take advantage of static_assert in the case it's built as C++11 or higher.



(Note: I know there are ways to do this in pre-C11 C, at least if you're willing to take a message parameter--though it won't work quite everywhere. But for the sake of argument let's say I have some legitimate need to make it take no message, and be a no-op in at least some C builds.)



So here was the simple definition I tried:



#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond)
#endif


There's no semicolon in the macro, with the intent that you would add it at the callsite. But under pedantic C warning settings, this macro appearing in global scope causes:




error: ISO C does not allow extra ‘;’ outside of a function [-Werror=pedantic]




The easy solution seems to be to take the semicolon off the callsites, and put it in the C++11 side of the macro. But I wonder: how do you make a no-op macro in global scope which allows a semicolon at the callsite (without running afoul of some other warning)?







c c89 static-assert






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 25 '18 at 16:45

























asked Dec 25 '18 at 15:40









HostileFork

25.4k777133




25.4k777133







  • 3




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    Dec 25 '18 at 16:29










  • @RaymondChen It seems in some compiler/warning combinations you get warnings about having forward function declarations more than once. You can disable those, but assuming they are there for a good reason...the struct solution below doesn't appear to trigger any warnings.
    – HostileFork
    Dec 25 '18 at 16:42













  • 3




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    Dec 25 '18 at 16:29










  • @RaymondChen It seems in some compiler/warning combinations you get warnings about having forward function declarations more than once. You can disable those, but assuming they are there for a good reason...the struct solution below doesn't appear to trigger any warnings.
    – HostileFork
    Dec 25 '18 at 16:42








3




3




#define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
– Raymond Chen
Dec 25 '18 at 16:29




#define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
– Raymond Chen
Dec 25 '18 at 16:29












@RaymondChen It seems in some compiler/warning combinations you get warnings about having forward function declarations more than once. You can disable those, but assuming they are there for a good reason...the struct solution below doesn't appear to trigger any warnings.
– HostileFork
Dec 25 '18 at 16:42





@RaymondChen It seems in some compiler/warning combinations you get warnings about having forward function declarations more than once. You can disable those, but assuming they are there for a good reason...the struct solution below doesn't appear to trigger any warnings.
– HostileFork
Dec 25 '18 at 16:42













1 Answer
1






active

oldest

votes


















14














Since forward declarations of structures may be repeated as much as we want, you can use a dummy declaration:



#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick


@JonathanLeffler says this should work in older compilers, even pre-C11...but:




"If you have a C90 compiler, it would object if you had a static assert after a statement in a compound statement. This is not your primary concern (it’ll always be OK at file scope if the static assert is OK too), but it isn’t limited to being used at file scope. The risk is low, though"




For related situations that might not be entirely no-ops at compile-time, C11 introduced the ability to repeat typedefs. And as in the post linked about static asserts in C prior to _Static_assert() shows, there are ways to get around typedef duplication for older C using the line number or another disambiguator:



/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b

#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif


So long as static assertions appear one per line the identifiers won't conflict with each other.






share|improve this answer


















  • 3




    There is no need for __LINE__ or concatenation. Type definitions may be repeated, so any name that will not be otherwise used is fine; one can use typedef void VoidTypeKludge.
    – Eric Postpischil
    Dec 25 '18 at 16:00






  • 4




    You could also just use struct StaticAssertSurrogate as the replacement text, which will work with compilers older than C11 (which is when it became possible to repeat a typedef). It doesn't even matter whether the structure tag exists as a real structure type.
    – Jonathan Leffler
    Dec 25 '18 at 16:04











  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    Dec 25 '18 at 16:06






  • 1




    C11 §6.7 Declarations ¶3. The wording about a typedef name may be redefined to denote the same type as it currently does is new.
    – Jonathan Leffler
    Dec 25 '18 at 16:13











  • @HostileFork - I stepped out shortly after editing the alternative in. I marked it as CW though (only thing that's relatively easy on mobile). If you don't mind, make the edit. Or I'll get back to it later.
    – StoryTeller
    Dec 25 '18 at 16:25











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
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53923706%2fworkaround-for-semicolon-in-global-scope-warning-for-no-op-c-macro%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









14














Since forward declarations of structures may be repeated as much as we want, you can use a dummy declaration:



#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick


@JonathanLeffler says this should work in older compilers, even pre-C11...but:




"If you have a C90 compiler, it would object if you had a static assert after a statement in a compound statement. This is not your primary concern (it’ll always be OK at file scope if the static assert is OK too), but it isn’t limited to being used at file scope. The risk is low, though"




For related situations that might not be entirely no-ops at compile-time, C11 introduced the ability to repeat typedefs. And as in the post linked about static asserts in C prior to _Static_assert() shows, there are ways to get around typedef duplication for older C using the line number or another disambiguator:



/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b

#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif


So long as static assertions appear one per line the identifiers won't conflict with each other.






share|improve this answer


















  • 3




    There is no need for __LINE__ or concatenation. Type definitions may be repeated, so any name that will not be otherwise used is fine; one can use typedef void VoidTypeKludge.
    – Eric Postpischil
    Dec 25 '18 at 16:00






  • 4




    You could also just use struct StaticAssertSurrogate as the replacement text, which will work with compilers older than C11 (which is when it became possible to repeat a typedef). It doesn't even matter whether the structure tag exists as a real structure type.
    – Jonathan Leffler
    Dec 25 '18 at 16:04











  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    Dec 25 '18 at 16:06






  • 1




    C11 §6.7 Declarations ¶3. The wording about a typedef name may be redefined to denote the same type as it currently does is new.
    – Jonathan Leffler
    Dec 25 '18 at 16:13











  • @HostileFork - I stepped out shortly after editing the alternative in. I marked it as CW though (only thing that's relatively easy on mobile). If you don't mind, make the edit. Or I'll get back to it later.
    – StoryTeller
    Dec 25 '18 at 16:25
















14














Since forward declarations of structures may be repeated as much as we want, you can use a dummy declaration:



#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick


@JonathanLeffler says this should work in older compilers, even pre-C11...but:




"If you have a C90 compiler, it would object if you had a static assert after a statement in a compound statement. This is not your primary concern (it’ll always be OK at file scope if the static assert is OK too), but it isn’t limited to being used at file scope. The risk is low, though"




For related situations that might not be entirely no-ops at compile-time, C11 introduced the ability to repeat typedefs. And as in the post linked about static asserts in C prior to _Static_assert() shows, there are ways to get around typedef duplication for older C using the line number or another disambiguator:



/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b

#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif


So long as static assertions appear one per line the identifiers won't conflict with each other.






share|improve this answer


















  • 3




    There is no need for __LINE__ or concatenation. Type definitions may be repeated, so any name that will not be otherwise used is fine; one can use typedef void VoidTypeKludge.
    – Eric Postpischil
    Dec 25 '18 at 16:00






  • 4




    You could also just use struct StaticAssertSurrogate as the replacement text, which will work with compilers older than C11 (which is when it became possible to repeat a typedef). It doesn't even matter whether the structure tag exists as a real structure type.
    – Jonathan Leffler
    Dec 25 '18 at 16:04











  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    Dec 25 '18 at 16:06






  • 1




    C11 §6.7 Declarations ¶3. The wording about a typedef name may be redefined to denote the same type as it currently does is new.
    – Jonathan Leffler
    Dec 25 '18 at 16:13











  • @HostileFork - I stepped out shortly after editing the alternative in. I marked it as CW though (only thing that's relatively easy on mobile). If you don't mind, make the edit. Or I'll get back to it later.
    – StoryTeller
    Dec 25 '18 at 16:25














14












14








14






Since forward declarations of structures may be repeated as much as we want, you can use a dummy declaration:



#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick


@JonathanLeffler says this should work in older compilers, even pre-C11...but:




"If you have a C90 compiler, it would object if you had a static assert after a statement in a compound statement. This is not your primary concern (it’ll always be OK at file scope if the static assert is OK too), but it isn’t limited to being used at file scope. The risk is low, though"




For related situations that might not be entirely no-ops at compile-time, C11 introduced the ability to repeat typedefs. And as in the post linked about static asserts in C prior to _Static_assert() shows, there are ways to get around typedef duplication for older C using the line number or another disambiguator:



/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b

#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif


So long as static assertions appear one per line the identifiers won't conflict with each other.






share|improve this answer














Since forward declarations of structures may be repeated as much as we want, you can use a dummy declaration:



#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick


@JonathanLeffler says this should work in older compilers, even pre-C11...but:




"If you have a C90 compiler, it would object if you had a static assert after a statement in a compound statement. This is not your primary concern (it’ll always be OK at file scope if the static assert is OK too), but it isn’t limited to being used at file scope. The risk is low, though"




For related situations that might not be entirely no-ops at compile-time, C11 introduced the ability to repeat typedefs. And as in the post linked about static asserts in C prior to _Static_assert() shows, there are ways to get around typedef duplication for older C using the line number or another disambiguator:



/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b

#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond)
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif


So long as static assertions appear one per line the identifiers won't conflict with each other.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 25 '18 at 16:39


























community wiki





3 revs, 2 users 68%
StoryTeller








  • 3




    There is no need for __LINE__ or concatenation. Type definitions may be repeated, so any name that will not be otherwise used is fine; one can use typedef void VoidTypeKludge.
    – Eric Postpischil
    Dec 25 '18 at 16:00






  • 4




    You could also just use struct StaticAssertSurrogate as the replacement text, which will work with compilers older than C11 (which is when it became possible to repeat a typedef). It doesn't even matter whether the structure tag exists as a real structure type.
    – Jonathan Leffler
    Dec 25 '18 at 16:04











  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    Dec 25 '18 at 16:06






  • 1




    C11 §6.7 Declarations ¶3. The wording about a typedef name may be redefined to denote the same type as it currently does is new.
    – Jonathan Leffler
    Dec 25 '18 at 16:13











  • @HostileFork - I stepped out shortly after editing the alternative in. I marked it as CW though (only thing that's relatively easy on mobile). If you don't mind, make the edit. Or I'll get back to it later.
    – StoryTeller
    Dec 25 '18 at 16:25













  • 3




    There is no need for __LINE__ or concatenation. Type definitions may be repeated, so any name that will not be otherwise used is fine; one can use typedef void VoidTypeKludge.
    – Eric Postpischil
    Dec 25 '18 at 16:00






  • 4




    You could also just use struct StaticAssertSurrogate as the replacement text, which will work with compilers older than C11 (which is when it became possible to repeat a typedef). It doesn't even matter whether the structure tag exists as a real structure type.
    – Jonathan Leffler
    Dec 25 '18 at 16:04











  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    Dec 25 '18 at 16:06






  • 1




    C11 §6.7 Declarations ¶3. The wording about a typedef name may be redefined to denote the same type as it currently does is new.
    – Jonathan Leffler
    Dec 25 '18 at 16:13











  • @HostileFork - I stepped out shortly after editing the alternative in. I marked it as CW though (only thing that's relatively easy on mobile). If you don't mind, make the edit. Or I'll get back to it later.
    – StoryTeller
    Dec 25 '18 at 16:25








3




3




There is no need for __LINE__ or concatenation. Type definitions may be repeated, so any name that will not be otherwise used is fine; one can use typedef void VoidTypeKludge.
– Eric Postpischil
Dec 25 '18 at 16:00




There is no need for __LINE__ or concatenation. Type definitions may be repeated, so any name that will not be otherwise used is fine; one can use typedef void VoidTypeKludge.
– Eric Postpischil
Dec 25 '18 at 16:00




4




4




You could also just use struct StaticAssertSurrogate as the replacement text, which will work with compilers older than C11 (which is when it became possible to repeat a typedef). It doesn't even matter whether the structure tag exists as a real structure type.
– Jonathan Leffler
Dec 25 '18 at 16:04





You could also just use struct StaticAssertSurrogate as the replacement text, which will work with compilers older than C11 (which is when it became possible to repeat a typedef). It doesn't even matter whether the structure tag exists as a real structure type.
– Jonathan Leffler
Dec 25 '18 at 16:04













@JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
– StoryTeller
Dec 25 '18 at 16:06




@JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
– StoryTeller
Dec 25 '18 at 16:06




1




1




C11 §6.7 Declarations ¶3. The wording about a typedef name may be redefined to denote the same type as it currently does is new.
– Jonathan Leffler
Dec 25 '18 at 16:13





C11 §6.7 Declarations ¶3. The wording about a typedef name may be redefined to denote the same type as it currently does is new.
– Jonathan Leffler
Dec 25 '18 at 16:13













@HostileFork - I stepped out shortly after editing the alternative in. I marked it as CW though (only thing that's relatively easy on mobile). If you don't mind, make the edit. Or I'll get back to it later.
– StoryTeller
Dec 25 '18 at 16:25





@HostileFork - I stepped out shortly after editing the alternative in. I marked it as CW though (only thing that's relatively easy on mobile). If you don't mind, make the edit. Or I'll get back to it later.
– StoryTeller
Dec 25 '18 at 16:25


















draft saved

draft discarded
















































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.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • 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.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53923706%2fworkaround-for-semicolon-in-global-scope-warning-for-no-op-c-macro%23new-answer', 'question_page');

);

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






Popular posts from this blog

How to check contact read email or not when send email to Individual?

Displaying single band from multi-band raster using QGIS

How many registers does an x86_64 CPU actually have?