当我设置-Wall标志时,GCC说 snr_db 未使用,但使用了此变量。当我在for的范围之外初始化它时,gcc会停止警告我。有谁知道为什么会这样?
double snr_db;
double snr_db_step = #WHATHEVER
for (int interval = 1, snr_db = 20.0; interval <= intervals; interval++, snr_db -= snr_db_step) {
snr_lin = pow(10.0, snr_db / 10.0);
bit_err_rate = ber_bpsk(snr_lin);
//CODE CONTINUES
}
答案 0 :(得分:12)
实际上没有使用它。你宣布它为double
-
double snr_db; // this is unused
但是在for
循环 -
for (int interval = 1, snr_db = 20.0; ..)
此snr_db
int
在这里{与int x,y;
相同,两者都是int
,是声明的一部分)在阴影上,在这个循环体上面声明了一个。
因此,double snr_db;
仍未使用。
你可以这样做 -
double snr_db;
int interval;
for(interval = 1, snr_db =20.0;..){....} // only intialization
/* ^^^^^^^^^^^^^^^^^^^^^^^^ this would be a different case from above as here
',' does work as comma operator therefore, evaluating both the expressions. */
答案 1 :(得分:5)
您的for
循环声明了两个 int
个变量,其中包括一个(同样容易引起混淆的snr_db
)变量,它们会遮蔽外部double
一个嵌套的词汇scope。所以海湾合作委员会是对的。
(根据经验,相信GCC编译器提供的警告经过极度测试和同行评审,因此信任编译器比您自己的代码更多)功能
您应该在 snr_db = 20.0;
循环之前指定for
,在您的情况下,这是唯一理智的事情。
您可以使用comma operator,但这会使您的代码无法读取:
for (int interval = (snr_db = 20.0), 1; ///unreadable so confusing
因此我不建议这样做。
答案 2 :(得分:4)
现有答案已经解决了问题的根源:此for
循环
for (int interval = 1, snr_db = 20.0; [...]; [...]) {
声明两个int
类型的变量,其中一个碰巧隐藏了外部作用域的double snr_db
。为了更深入的理解,让我们添加一些背景知识。
来自 N1570 (latest draft for C11),§6.8.5.3p1:
声明
for
(
clause-1;
expression-2;
expression-3 < / em>)
声明表现如下:表达式 expression-2 是控制表达式 在每次执行循环体之前进行评估。表达式表达式-3 是 在每次执行循环体后评估为void表达式。如果 clause-1 是a 声明,它声明的任何标识符的范围是声明的剩余部分 整个循环,包括其他两个表达式;它是按执行顺序到达的 在第一次评估控制表达之前。如果 clause-1 是一个表达式,那就是 在第一次评估控制表达之前评估为空表达。
因此,对于for
,子句-1 可以是声明或表达式。在您的示例中,它是声明。在声明中,逗号具有分隔多个声明符的含义,声明多个相同类型的对象。
另一方面,在表达式中,逗号是一个运算符,它计算两个操作数 sequenced ,并且评估结果是右侧操作数的结果。这通常也用在for
循环中。由于子句-1 被评估为空表达式,结果无关紧要,只有副作用是相关的。因此,正确编写代码的一种方法如下:
[...]
int interval;
for (interval = 1, snr_db = 20.0; [...]; [...]) {
现在, clause-1 是一个表达式,逗号运算符分隔两个不同的赋值表达式(具有为变量设置新值的副作用)。但是这种形式的缺点是interval
的范围不必要地扩展到你的循环范围。
当然,声明可以在其初始值设定项中包含 表达式,因此有一种方法可以将完全写入你的内容原本想要的看起来像这样:
for (int interval = (snr_db = 20.0), 1; [...]; [...]) {
现在,只声明interval
并且其初始值设定项使用逗号运算符首先执行snr_db = 20.0
的副作用,但仍然评估为1
(右侧)逗号的一边)来初始化interval
。虽然这是正确的,但作为高级C程序员,您应该了解它是如何工作的,从不在实践中编写此类代码。要求即使是经验丰富的程序员停下来思考阅读代码时究竟是做什么,这太令人困惑了。
因此,最好的选择是将interval
的声明保留为子句-1 ,并在循环之前将作业移至snr_db
:
snr_db = 20.0;
for (int interval = 1; [...]; [...]) {
答案 3 :(得分:0)
因为for循环中的snr_db是临时变量,而不是外部作用域变量。