首页
学习
活动
专区
圈层
工具
发布

gcc优化
EN

Stack Overflow用户
提问于 2012-06-22 07:38:47
回答 6查看 1.4K关注 0票数 3

我想知道下面的代码是否会在编译时抛出错误或警告,并启用任何类型的gcc/g++优化。

代码语言:javascript
复制
int a;
a = func();
if (a == 2) {
    assert(false);
}

我认为下面的代码可以在发布配置中抛出一个警告"set但未使用的变量“。

代码语言:javascript
复制
int a;
a = func();
assert(a != 2);

但是上面的代码呢?(gcc 可以删除if语句本身,因为if语句或if块(在版本构建中)将不会执行任何操作,然后抛出一个警告“未使用但设置变量”)。

编辑:这绝对不是一个关于减少代码或执行文件大小的问题。我想知道在任何构建配置中成功的一段代码。

编辑:我们在发布模式中禁用断言。

EN

回答 6

Stack Overflow用户

发布于 2012-06-22 08:13:09

根据我的测试,下面的代码使用-Wall -Wextra -O2 -DNDEBUG生成一个警告

代码语言:javascript
复制
int a = func(); // warning: unused variable ‘a’
assert(a != 2);

但以下代码没有:

代码语言:javascript
复制
// no warnings
int a;
a = func();
assert(a != 2);

但是,可以始终通过将变量转换为void来抑制未使用的变量警告。

代码语言:javascript
复制
int a = func();
(void) a; // suppresses "unused variable" warning
assert(a != 2);

据我所知,行a = func()语句始终算作变量a的使用,而初始化不算作使用。

我不会试图对冲未来可能的编译器警告随着编译器的改变和他们的诊断改进,因为对冲有时可以抑制有效的警告偶然。

如何定义断言?

标准委员会和C实现者仔细地设计了assert,这样它就不会产生虚假的警告。注意到void的转换是多么的常见..。

在没有

  • 的情况下,glibc大致按照以下方式定义assert (除了abort以外的其他内容):

#定义断言(费用)((费用)?(void) 0: abort())

  • With NDEBUG,glibc以这种方式定义它(按照C标准的要求):

#定义断言(Expr) ((void) 0)

  • 以下assert定义不兼容,因为它不扩展为表达式:

#定义断言(expr) { if (Expr){.} //错误的

C++的定义也略有不同。因此,您可以看到,assert的定义是正确的,因此它不会创建任何虚假的编译器警告,而且它的语法行为确实像函数调用。

票数 4
EN

Stack Overflow用户

发布于 2012-06-22 08:03:33

一般来说,不可能说一段代码永远不会收到编译器的警告,因为将来可能会添加新的警告,或者编译器错误可能导致虚假的警告。

我确信GCC不会对用大括号定义的空if体发出警告,这正是因为在有效的代码中很容易出现这种情况(这在本质上非常类似于您的情况):

代码语言:javascript
复制
int a = func();
if (a == 2)
{
#ifdef SOME_BUILD_SETTING
    launch_missiles();
#endif
}

手册显示

-body body

如果在ifelsedo while语句中出现空体,则会发出警告。-Wextra也启用了此警告。

它将申请:

代码语言:javascript
复制
#ifdef SOME_BUILD_OPTION
# define LAUNCH_MISSILES launch_missiles()
#else
# define LAUNCH_MISSILES
#endif
if (a==2)
  LAUNCH_MISSILES;

然后用-Wextra编译,而不定义SOME_BUILD_OPTION

但是有了大括号,它就不会发出警告,正如Dietrich Epp评论的那样,对于assert,它不会发出警告,因为即使定义了NDEBUG,它也不会扩展到零。

在您的代码中,a被初始化并使用它的值,所以我会很惊讶它会发出警告。

票数 1
EN

Stack Overflow用户

发布于 2012-06-22 08:24:07

如果您的assert被预处理器移除,这可能会导致问题,如下所示:

代码语言:javascript
复制
#ifdef ENABLE_ASSERT
#define assert (CONDITION) {if (!(CONDITION)) abort ();}
#else
#define assert (CONDITION) /* Nothing */
#endif

但是,如果你做得好,就不会有问题:

代码语言:javascript
复制
#define assert (CONDITION) {if ((ENABLE_ASSERT) && !(CONDITION)) abort ();}

在这种情况下,编译器仍然会看到aCONDITION中使用,但在ENABLE_ASSERT为零时将优化它。与使用预处理器相比,让编译器优化器删除代码通常更好:它避免了类似这样的警告,并且通常会导致更易读的代码,而且如果有一天代码变成运行时测试,则不需要重写代码。

显然,必须始终将ENABLE_ASSERT定义为零或非零.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11152040

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档