一个简单C程序的奇怪行为
如果我运行以下代码,一个简单C程序的奇怪行为,c,arrays,pre-increment,C,Arrays,Pre Increment,如果我运行以下代码,graph[0][0]获取1,而graph[0][1]获取4 换句话说,线图[0][++graph[0][0]]=4将1放入图形[0][0]中,将4放入图形[0][1] 如果有人能提供合理的解释,我将不胜感激 我从Visual C++ 2015和Android C编译器(CPPRIDOD)中观察到这一点。 让我们把它分解一下: ++graph[0][0] 这预先增加了图形[0][0]处的值,这意味着现在图形[0][0]=1,然后表达式的值是1(因为这是图形[0][0]的最终
graph[0][0]
获取1
,而graph[0][1]
获取4
换句话说,线图[0][++graph[0][0]]=4
将1
放入图形[0][0]
中,将4
放入图形[0][1]
如果有人能提供合理的解释,我将不胜感激
我从Visual C++ 2015和Android C编译器(CPPRIDOD)中观察到这一点。 让我们把它分解一下:
++graph[0][0]
这预先增加了图形[0][0]
处的值,这意味着现在图形[0][0]=1
,然后表达式的值是1
(因为这是图形[0][0]
的最终值)
那么
graph[0][/*previous expression = 1*/] = 4;
基本上,图[0][1]=4代码>
就这样!现在图形[0][0]=1
和图形[0][1]=4
您正在通过执行++graph[0][0]
向图形[0][0]
添加一个。然后将图形[0][1]
设置为4
。也许您想先执行graph[0][graph[0][0]+1]=4
首先,您的变量graph[10][10]
是静态的,因此将使用值0
初始化它
然后直线图[0][++图[0][0]]=4
这里graph[0][0]=0在表达式中,您只需增加graph[0][0]的值,因此基本上指定graph[0][1]=4代码>你自己
请注意,您使用了增量前运算符(++x),因此它首先会递增,值也会更改,但如果您要使用增量后运算符(x++),则图形[0][0]=4代码>本身
首先让我们看看一元(前缀)递增运算符的作用
前缀++运算符的操作数值递增。结果是递增后操作数的新值
那么,万一
graph[0][++graph[0][0]] = 4;
首先,将图形[0][0]
的值增加1,然后将该值用于索引
现在,graph
是一个静态全局变量,由于隐式初始化,数组中的所有成员默认初始化为0
。因此,++graph[0][0]
将graph[0][0]
的值递增为1,并返回1
的值
然后,该指令的简化版本如下
graph[0][1] = 4;
因此,你得到
图形[0][0]
为1
图形[0][1]
如图4所示
另外,FWIW,main()
的建议签名是intmain(void)
让我们把这个表达式的事实列出来
graph[0][++graph[0][0]] = 4;
- 根据6.5.1,数组索引
++图[0][0]
的计算在数组元素图[0][++图[0][0]]
的计算之前排序,而数组元素图[0][0]
的计算又在整个赋值运算符的计算之前排序
++graph[0][0]
的值必须是1
。请注意,这并不意味着整个预增量及其副作用必须“先发生”。这仅仅意味着必须首先计算预增量(即1
)的结果。图形[0][0]
的实际修改(即将图形[0][0]
从0
更改为1
)可能要晚得多。没有人知道什么时候会发生(在声明结束前的某个时候)
- 这意味着赋值运算符修改的元素是
图形[0][1]
。这就是4
应该去的地方。将4
赋值给graph[0][1]
也是=
运算符的一个副作用,它将在语句结束前的某个时间发生
注意,在这种情况下,我们可以最终确定++
修改图形[0][0]
,而=
修改图形[0][1]
。我们有两个未排序的副作用(这是危险的),但它们作用于两个不同的对象(这使它们安全)。这正是我们在这种情况下避免未定义行为的原因
但是,这取决于graph
array的初始值。如果你试试这个
graph[0][0] = -1;
graph[0][++graph[0][0]] = 4;
行为将立即变得未定义,即使表达式本身看起来相同。在这种情况下,++
的副作用和=
的副作用应用于同一数组元素图形[0][0]
。副作用之间没有顺序关系,这意味着行为是未定义的。阅读并避免编写这种不可读的代码。@BasileStarynkevitch先生,这真的是UB吗?我们不是在不同的元素上操作吗?@BasileStarynkevitch这一个看起来定义很好,因为它使用了预增量。如果它是graph[0][graph[0][0]+]=4
,它将是一个UB。类似地,将-1
存储在图形[0][0]
中会导致UB带有前置增量。但它仍然非常隐蔽,无法读取。而一个小小的改变就可以让这一切变得更美好。请看Sasblinklight的评论。@AnT您能解释一下吗?你所说的在没有订单的情况下强加订单是什么意思?这不是未定义的行为。@Jashaszun:不,这不是未定义的行为。但是你声称“现在图[0][0]=1
”有误导性。无需在原始表达式的上下文中计算++graph[0][0]
,即可立即修改graph[0][0]
。所有这些++
所做的就是生成值1
,并将其发送到求值链上,但您不能声称“现在graph[0][0]=1
”。很可能图形[0][0]
会保持0
一段时间。它将在很久以后(在完整语句结束之前)变为1
。C语言不保证exa何时运行
graph[0][0] = -1;
graph[0][++graph[0][0]] = 4;