Workaround for “semicolon in global scope” warning for no-op C macro
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
add a comment |
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
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
add a comment |
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
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
c c89 static-assert
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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.
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 usetypedef void VoidTypeKludge
.
– Eric Postpischil
1 hour ago
3
You could also just usestruct 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
|
show 1 more 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%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
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.
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 usetypedef void VoidTypeKludge
.
– Eric Postpischil
1 hour ago
3
You could also just usestruct 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
|
show 1 more comment
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.
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 usetypedef void VoidTypeKludge
.
– Eric Postpischil
1 hour ago
3
You could also just usestruct 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
|
show 1 more comment
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.
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.
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 usetypedef void VoidTypeKludge
.
– Eric Postpischil
1 hour ago
3
You could also just usestruct 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
|
show 1 more comment
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 usetypedef void VoidTypeKludge
.
– Eric Postpischil
1 hour ago
3
You could also just usestruct 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
|
show 1 more 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.
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.
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%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
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
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