https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html
在定义宏的时候,可能会加大括号,此时如果在使用宏的语句后面习惯性的加分号,就可能导致一个空语句的出现。这个空语句的危害性是在于if block的写法。具体见上面的说明。
有些静态代码检查工具,可以帮助检查这样的格式,以避免隐藏问题的出现。比如sonarqube。
gcc给出的方法是使用 do {…} while (0) 这种方式来消除这个可能出现的多余分号。这种方式是可以消除空语句对于if-else的影响。
见到的另外一种是在googletest里看到的,使用static_assert。这种不能消除对于分号的影响。但是可以消除静态代码检查的警告。但是需要明确知道这个不会被用于if-else语句的简写格式。因为只是变量定义,应该不会用if-else的简写格式。
// Macros for declaring flags.
#define GMOCK_DECLARE_bool_(name)
namespace testing {
GTEST_API_ extern bool GMOCK_FLAG(name);
} static_assert(true, “no-op to require trailing semicolon”)
这里的疑问就是,这里的问题关键是“The presence of two statements—the compound statement and a null statement—in between the if condition and the else makes invalid C code. ” 空语句和其他语句一块被解释成了多语句,导致if的简写方式出现问题。
那编译器是否可以作为改进的对象,对这种空语句做特殊处理。将空语句在编译之前去掉,完全可以避免if语句的错误。当然要考虑标准是允许空语句存在的,例如:
# define GTEST_CHECK_(condition) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::internal::IsTrue(condition)) \
; \
编译时可能出现的错误
abc.c:14:2: error: ‘else’ without a previous ‘if’
else
^~~~
abc.c:17:2: error: expected declaration or statement at end of input
return 0;
运行时错误就可能是逻辑错误。
#ifdef IO_DEBUG
# define CHECK_FILE(FILE, RET) do { \
if ((FILE) == NULL \
|| ((FILE)->_flags & _IO_MAGIC_MASK) != _IO_MAGIC) \
{ \
__set_errno (EINVAL); \
return RET; \
} \
} while (0)
#else
# define CHECK_FILE(FILE, RET) do { } while (0)
#endif