问题Declaration difference?有人问到
之间有什么区别int i;
for (i=0; i<100; i++) {
//some loop....
}
和
for (int i=0; i<100; i++) {
//some loop....
}
答案很明确;第二个是C99,i
的范围仅限于循环。我没有C99所以我无法测试,因此问一个问题:在下列情况下解决方案是什么:
int i = 32;
for (int i=i; i<100; i++) {
// some loop
}
“新”i
是否会使用“旧”i
进行初始化?或者旧的i
已经无法访问,因为已经宣布了新的i
?
答案 0 :(得分:10)
在这个for循环语句中
int i = 32;
for (int i = i; i < 100; i++) {
// some loop
}
在for语句中声明的变量i
具有不确定的值。问题是,只要定义了一个声明符(在这种情况下它由标识符i
组成),它就会在给定的作用域中隐藏一个具有相同名称的实体。所以在这个宣言中
int i = i;
变量i指的是=
的右侧。
另一个类似的例子。我们假设你有一个typedef。
typedef int Int;
您可以在定义后写作
Int Int;
在这种情况下,类型为Int
的对象的名称Int
隐藏了typedef定义,您可能还没有编写
Int Another_Int;
因为编译器会发出错误。
根据C标准(6.2.1标识符范围)
4 ...如果声明者或声明的声明的类型说明符 标识符出现在块内或参数列表中 函数定义中的声明,标识符有块作用域, 它终止于相关块的末尾。
更清楚的是在C ++标准(3.3.2声明点)中写的
1名称的声明点紧随其后 完整的声明者(第8条)和初始化者(如果有的话), 除非如下所述。 [例如:
int x = 12;
{ int x = x; }
这里第二个x用它自己的(不确定的)值初始化。 - 例子]
请在此代码段中考虑
int i = 10;
{
int i[i];
}
在复合语句中,声明数组int i[10];
,外部变量i
用作数组大小,因为内部变量i
仅在其声明符完成时才会声明。
答案 1 :(得分:8)
参见C11 6.8.5.3:“如果子句-1是一个声明,它声明的任何标识符的范围是声明的剩余部分和整个循环,包括其他两个表达式”。
第二个i
是指定义的i
,而不是旧的。{/ p>
整个事情是 UB ,因为你使用的是i
(在循环中定义的i
)的值而没有先前的赋值(或初始化)。< / p>
使用工作(但不同)示例编辑
您仍然可以通过使用指针
来使用旧值int i = 42;
int *old_i = &i;
for (int i = *old_i; i < 50; i++) printf("%d ", i);
答案 2 :(得分:5)
不,在任何情况下都像
int i=i;
是一个坏主意,因为第二个i
与第一个int tmp=i, i=tmp;
是同一个对象,但仍未初始化。
如果你坚持要做一些像
这样的事情<country>United Kingdom</country>
<countryCode>UK</countryCode>
<region>Bristol</region>
<ip>xx.xx.xx.x</ip>
<ISP>VodafoneM</ISP>
获得你想要的效果。
答案 3 :(得分:2)
感谢Jens Gustedt,我做了一些研究,这是我发现的:以下代码:
NewNewsAdapter adapters = new NewNewsAdapter(getActivity().getApplicationContext(), R.layout.newnews, newsList);
listedView.setAdapter(adapters);
adapters.notifyDataSetChanged();
produce this assembly与gcc 5.2:
#include<stdio.h>
int main()
{
int i = 32;
for (int i=i; i<50; i++) {
printf("Hello World %d", i); // <-- this is the new i, the other one is not accessible here
}
return 0;
}
用于循环的变量是.LC0:
.string "Hello World %d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-8], 32
.L3:
cmp DWORD PTR [rbp-4], 49
jg .L2
mov eax, DWORD PTR [rbp-4]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
add DWORD PTR [rbp-4], 1
jmp .L3
.L2:
mov eax, 0
leave
ret
,它没有被初始化,可以是任何东西。所以它确实是一个UB。