假设我们有这样的代码:
int check(){
int x = 5;
++x; /* line 1.*/
return 0;
}
int main(){
return check();
}
如果注释掉了line 1
并且启动了编译器并启用了所有警告,则会发出:
warning: unused variable ‘x’ [-Wunused-variable]
但是,如果我们取消评论line 1
,即增加x,则不会发出警告。
为什么?增加变量并没有真正使用它。
答案 0 :(得分:6)
是
x++
与作业x = x+1;
相同。当您分配某些内容时,您可能无法跳过使用它。结果是不被丢弃。
此外,来自online gcc manual,关于-Wunused-variable
选项
除了声明之外,本地或静态变量未使用时发出警告。
因此,当您对x++;
发表评论时,它会满足生成和发出警告消息的条件。当您取消注释时,编译器可以看到该用法(此特定“用法”的“有用性”值得怀疑,但是,它仍然是一种用法)并且没有警告。
答案 1 :(得分:4)
使用preincrement,您将再次递增并将值再次赋值给变量。它就像:
x=x+1
正如gcc文档所说:
-Wunused变量: 除了声明之外,每当局部或静态变量未被使用时发出警告。
如果您评论该行,则表示您没有使用您声明它的行旁边的变量
答案 2 :(得分:3)
增加变量并没有真正使用它。
当然这是使用它。它对存储的对象进行读取和写入访问。此操作对您的简单玩具代码中的没有任何影响,优化程序可能会注意到并完全删除变量。但警告背后的逻辑要简单得多:警告 iff 从不使用变量。
这实际上有益于你可以在有意义的情况下使这个警告沉默:
void someCallback(void *data)
{
(void)data; // <- this "uses" data
// [...] handler code that doesn't need data
}
答案 3 :(得分:1)
为什么?增加变量并没有真正使用它。
是的,它确实在使用它。至少从语言的角度来看。我希望优化器删除变量的所有跟踪。
当然,特定用途对程序的其余部分没有影响,因此变量确实是多余的。我同意在这种情况下警告会有所帮助。但是,你提到的不是未使用警告的目的。
然而,考虑分析特定变量是否对程序的执行有任何影响是非常困难的。必须有一个点,编译器停止检查变量是否实际有用。看来,您测试的编译器生成警告的阶段仅检查变量是否至少使用一次。那曾经是增量操作。
答案 4 :(得分:1)
我认为对于使用&#39;这个词有一种误解。以及编译器对此的意义。如果你有一个++i
,你不仅要访问变量,你甚至要修改它,而AFAIK就算是&#39;使用&#39;。
编译器可以识别的内容有限制&#39;如何&#39;正在使用变量,如果这些陈述有意义。事实上,clang和gcc都会尝试删除不必要的语句,具体取决于-O
- 标志(有时过于激进)。但这些优化没有警告就会发生。
检测一个从未被访问或使用过的变量(没有进一步声明提及该变量)相当容易。
答案 5 :(得分:1)
我同意你的意见,可能会对此产生警告。我认为它并没有产生警告,因为编译器的开发人员并没有为处理这种情况而烦恼(尚未)。也许是因为它太复杂了。但也许他们将来会这样做(提示:你可以建议他们这个警告)。
编译器收到越来越多的警告。例如,GCC中有-Wunused-but-set-variable
(这是一个&#34;新的&#34;警告,2011年在GCC 4.6中引入),警告说:
void fn() {
int a;
a = 2;
}
所以期待这也发出警告是完全没问题的(这里没有任何不同,代码也没有任何用处):
void fn() {
int a = 1;
a++;
}
也许他们可以添加新警告,例如-Wmeaningless-variable
答案 6 :(得分:0)
根据C标准 ISO / IEC 9899:201x ,总是执行表达式评估以允许产生表达式的副作用,除非编译器不能足够确定除去它,程序执行不会改变。
5.1.2.3程序执行
在抽象机器中,所有表达式都按语义指定的方式进行计算。实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用并且没有产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用)。
删除行
++x;
编译器可以推断出局部变量x
已定义并初始化,但未使用。
添加时,表达式本身可以被视为void
表达式,必须评估副作用,如下所述:
6.8.3表达式和空语句
表达式语句中的表达式被计算为其副作用的void表达式。
另一方面,删除相对于未使用变量的编译器警告,将表达式转换为void非常常见。即对于函数中未使用的参数,您可以编写:
int MyFunc(int unused)
{
(void)unused;
...
return a;
}
在这种情况下,我们有一个引用符号unused
的void表达式。