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












6














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




















  • 1




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    31 mins ago










  • @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
    19 mins ago


















6














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




















  • 1




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    31 mins ago










  • @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
    19 mins ago
















6












6








6


1





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 16 mins ago

























asked 1 hour ago









HostileFork

25.3k777132




25.3k777132








  • 1




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    31 mins ago










  • @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
    19 mins ago
















  • 1




    #define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
    – Raymond Chen
    31 mins ago










  • @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
    19 mins ago










1




1




#define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
– Raymond Chen
31 mins ago




#define STATIC_ASSERT(cond) void never_called() -- the semicolon completes the forward declaration.
– Raymond Chen
31 mins ago












@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
19 mins ago






@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
19 mins ago














1 Answer
1






active

oldest

votes


















8














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
    1 hour ago






  • 3




    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
    57 mins ago












  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    54 mins ago






  • 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
    48 mins ago












  • @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
    35 mins ago













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









8














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
    1 hour ago






  • 3




    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
    57 mins ago












  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    54 mins ago






  • 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
    48 mins ago












  • @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
    35 mins ago


















8














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
    1 hour ago






  • 3




    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
    57 mins ago












  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    54 mins ago






  • 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
    48 mins ago












  • @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
    35 mins ago
















8












8








8






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 21 mins ago


























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
    1 hour ago






  • 3




    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
    57 mins ago












  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    54 mins ago






  • 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
    48 mins ago












  • @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
    35 mins ago
















  • 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
    1 hour ago






  • 3




    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
    57 mins ago












  • @JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
    – StoryTeller
    54 mins ago






  • 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
    48 mins ago












  • @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
    35 mins ago










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
1 hour ago




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
1 hour ago




3




3




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
57 mins ago






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
57 mins ago














@JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
– StoryTeller
54 mins ago




@JonathanLeffler - Thanks, I was just in the process of checking typedef redefinition rules in C89.
– StoryTeller
54 mins ago




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
48 mins ago






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
48 mins ago














@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
35 mins ago






@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
35 mins ago




















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

404 Error Contact Form 7 ajax form submitting

How to know if a Active Directory user can login interactively

TypeError: fit_transform() missing 1 required positional argument: 'X'