我想知道下面的代码是否会在启用任何类型的gcc / g优化的编译时抛出错误或警告 .
int a;
a = func();
if (a == 2) {
assert(false);
}
我认为以下代码可以在发布配置中发出警告“设置但未使用的变量” .
int a;
a = func();
assert(a != 2);
但是上面的代码怎么样? (gcc can 删除if语句本身,因为在if语句或if-block(在发布版本中)都不会执行任何操作,然后抛出警告"unused but set variable")
编辑:这绝对不是减少代码或exe的大小的问题 . 我想知道在任何构建配置中成功的一段代码 .
编辑:我们在发布模式下禁用断言
6 回答
两个代码块都可以,但我会优先:
是的,此代码可能会在将来的某个时间点发出一些奇怪的编译器设置警告 .
你的问题永远不会得到肯定的回答 . 它不可能 . 未来是不可预测的 . 即使在目前,编译器标志的数量代表组合爆炸,这可能很难完全分析 . 任何给你一个'是'答案的人都可能忽略了一些东西 .
现在,我将说一般(根据我的经验)编译器只发出代码实际看起来像什么的警告,而不是优化器完成它后的样子 . 是的,如果您运行优化器,它可能能够进行更深入的分析并找到更微妙的问题 . 但它不会开始标记你现在多余的构造,因为优化器能够完全删除它 .
所以,我认为你在这里大部分时间都是安全的,这与你从我这里得到的“是”很接近 .
如果预处理器删除了
assert
,这可能会导致问题,如下所示:但是,如果你做得恰当,那么就没有问题:
在这种情况下,编译器仍然会在
CONDITION
中看到a
,但是当ENABLE_ASSERT
为零时会将其优化掉 . 如果它有一天变成运行时测试,则需要重写它 .显然,
ENABLE_ASSERT
必须始终定义为零或非零 .您可能知道
assert
宏是使用宏NDEBUG
进行管理的 . 我认为使用#ifdef NDEBUG
的东西会更容易阅读并具有相同的效果 .根据我的测试,以下代码使用
-Wall -Wextra -O2 -DNDEBUG
生成警告:但是以下代码没有:
但是,您始终可以通过强制转换为
void
来抑制未使用的变量警告 .据我所知,行
a = func()
语句总是计为变量a
的使用,而初始化不算作使用 .我不打算在编译器改变及其诊断改进时对冲未来可能的编译器警告,因为对冲有时会无意中抑制有效警告 .
How is assert defined?
标准委员会和C实施者已经仔细设计了
assert
,因此它不会产生虚假警告 . 注意void
的常见演员阵容是......NDEBUG
,glibc大致按以下方式定义assert
(除了abort
之外的其他内容):NDEBUG
,glibc以这种方式定义它(按照C标准的要求):assert
的以下定义不符合,因为它不会扩展为表达式:C的定义也略有不同 . 所以你看,
assert
是以正确的方式定义的,所以它不会创建任何伪造的编译器警告,并且它确实在语法上表现得像函数调用 .通常不可能说一段代码永远不会从编译器得到任何警告,因为将来可能会添加新警告,或者编译器错误可能会导致虚假警告 .
我很确定GCC不会警告一个用大括号定义的空
if
主体,正是因为这很容易发生在有效的代码中,比如这个(这与你的情况非常相似):手册显示
哪个适用于:
然后使用
-Wextra
编译而不定义SOME_BUILD_OPTION
.但是有了大括号,它并没有发出警告,正如迪特里希·埃普所说的那样,即使用
NDEBUG
定义,它也不会扩展到零 .在你的代码
a
初始化并使用它的值,所以我会惊讶于它警告 .