C 为什么这些构造使用增量前后未定义的行为? #包括 内部主(空) { int i=0; i=i++++++i; printf(“%d\n”,i);//3 i=1; i=(i++); printf(“%d\n”,i);//2应该是1,不是吗? 挥发性INTU=0; u=u+++++u; printf(“%d\n”,u);//1 u=1; u=(u++); printf(“%d\n”,u);//2也应该是一,不是吗? 寄存器int v=0; v=v+++++v; printf(“%d\n”,v);//3(应与u相同?) int w=0; printf(“%d%d\n”,++w,w);//这不应该打印1吗 int x[2]={5,8},y=0; x[y]=y++; printf(“%d%d\n”,x[0],x[1]);//这不应该打印0 8或5 0吗? }
C有未定义行为的概念,即某些语言结构在语法上是有效的,但在代码运行时无法预测行为 据我所知,标准没有明确说明为什么存在未定义行为的概念。在我看来,这只是因为语言设计者希望在语义上有一定的回旋余地,而不是要求所有实现都以完全相同的方式处理整数溢出,这很可能会带来严重的性能成本,他们只是没有定义行为,因此如果编写导致整数溢出的代码,任何事情都可能发生 那么,考虑到这一点,为什么会出现这些“问题”?语言清楚地表明,某些事情会导致死亡。没有问题,没有“应该”的问题。如果当其中一个涉及的变量被声明为volatile时,未定义的行为发生了变化,那么这并不能证明或改变任何事情。它是未定义的;你不能对这种行为进行推理 你最有趣的例子是C 为什么这些构造使用增量前后未定义的行为? #包括 内部主(空) { int i=0; i=i++++++i; printf(“%d\n”,i);//3 i=1; i=(i++); printf(“%d\n”,i);//2应该是1,不是吗? 挥发性INTU=0; u=u+++++u; printf(“%d\n”,u);//1 u=1; u=(u++); printf(“%d\n”,u);//2也应该是一,不是吗? 寄存器int v=0; v=v+++++v; printf(“%d\n”,v);//3(应与u相同?) int w=0; printf(“%d%d\n”,++w,w);//这不应该打印1吗 int x[2]={5,8},y=0; x[y]=y++; printf(“%d%d\n”,x[0],x[1]);//这不应该打印0 8或5 0吗? },c,increment,undefined-behavior,operator-precedence,sequence-points,C,Increment,Undefined Behavior,Operator Precedence,Sequence Points,C有未定义行为的概念,即某些语言结构在语法上是有效的,但在代码运行时无法预测行为 据我所知,标准没有明确说明为什么存在未定义行为的概念。在我看来,这只是因为语言设计者希望在语义上有一定的回旋余地,而不是要求所有实现都以完全相同的方式处理整数溢出,这很可能会带来严重的性能成本,他们只是没有定义行为,因此如果编写导致整数溢出的代码,任何事情都可能发生 那么,考虑到这一点,为什么会出现这些“问题”?语言清楚地表明,某些事情会导致死亡。没有问题,没有“应该”的问题。如果当其中一个涉及的变量被声明为vol
#include <stdio.h>
int main(void)
{
int i = 0;
i = i++ + ++i;
printf("%d\n", i); // 3
i = 1;
i = (i++);
printf("%d\n", i); // 2 Should be 1, no ?
volatile int u = 0;
u = u++ + ++u;
printf("%d\n", u); // 1
u = 1;
u = (u++);
printf("%d\n", u); // 2 Should also be one, no ?
register int v = 0;
v = v++ + ++v;
printf("%d\n", v); // 3 (Should be the same as u ?)
int w = 0;
printf("%d %d\n", ++w, w); // shouldn't this print 1 1
int x[2] = { 5, 8 }, y = 0;
x[y] = y ++;
printf("%d %d\n", x[0], x[1]); // shouldn't this print 0 8? or 5 0?
}
是一个未定义行为的教科书示例(请参阅Wikipedia上的条目)。C有未定义行为的概念,即某些语言结构在语法上是有效的,但在代码运行时无法预测行为 据我所知,标准没有明确说明为什么存在未定义行为的概念。在我看来,这只是因为语言设计者希望在语义上有一定的回旋余地,而不是要求所有实现都以完全相同的方式处理整数溢出,这很可能会带来严重的性能成本,他们只是没有定义行为,因此如果编写导致整数溢出的代码,任何事情都可能发生 那么,考虑到这一点,为什么会出现这些“问题”?语言清楚地表明,某些事情会导致死亡。没有问题,没有“应该”的问题。如果当其中一个涉及的变量被声明为volatile时,未定义的行为发生了变化,那么这并不能证明或改变任何事情。它是未定义的;你不能对这种行为进行推理 你最有趣的例子是
#include <stdio.h>
int main(void)
{
int i = 0;
i = i++ + ++i;
printf("%d\n", i); // 3
i = 1;
i = (i++);
printf("%d\n", i); // 2 Should be 1, no ?
volatile int u = 0;
u = u++ + ++u;
printf("%d\n", u); // 1
u = 1;
u = (u++);
printf("%d\n", u); // 2 Should also be one, no ?
register int v = 0;
v = v++ + ++v;
printf("%d\n", v); // 3 (Should be the same as u ?)
int w = 0;
printf("%d %d\n", ++w, w); // shouldn't this print 1 1
int x[2] = { 5, 8 }, y = 0;
x[y] = y ++;
printf("%d %d\n", x[0], x[1]); // shouldn't this print 0 8? or 5 0?
}
是一个未定义行为的教科书示例(参见维基百科上的条目)。我认为C99标准的相关部分是6.5表达式,§2 在上一个序列点和下一个序列点之间,对象应有其存储值 通过表达式的求值最多修改一次。此外,先验值 应为只读,以确定要存储的值 和6.5.16分配操作员,§4: 未指定操作数的求值顺序。如果试图修改 赋值运算符的结果或在下一个序列点之后访问它的结果 行为是未定义的
我认为C99标准的相关部分是6.5表达式,§2 在上一个序列点和下一个序列点之间,对象应有其存储值 通过表达式的求值最多修改一次。此外,先验值 应为只读,以确定要存储的值 和6.5.16分配操作员,§4: 未指定操作数的求值顺序。如果试图修改 赋值运算符的结果或在下一个序列点之后访问它的结果 行为是未定义的
只要编译和反汇编你的代码行,如果你很想知道它到底是什么,你就会得到你想要的 这是我在我的机器上得到的,以及我认为正在发生的事情:
u = (u++);
$cat evil.c
虚无罪恶{
int i=0;
i++=i+++++i;
}
$gcc evil.c-c-o evil.bin
$gdb.bin
(gdb)分解邪恶
函数邪恶的汇编程序代码转储:
0x00000000:推送%ebp
0x00000001:mov%esp,%ebp
0x00000003:子$0x10,%esp
0x00000006:movl$0x0,-0x4(%ebp)//i=0 i=0
0x0000000d:addl$0x1,-0x4(%ebp)//i++i=1
0x00000011:mov-0x4(%ebp),%eax//j=i=1 j=1
0x00000014:添加%eax,%eax//j+=j i=1 j=2
0x00000016:添加%eax,-0x4(%ebp)//i+=ji=3
0x00000019:addl$0x1,-0x4(%ebp)//i++i=4
0x0000001d:离开
0x0000001e:ret
汇编程序转储结束。
(我……假设0x00000014指令是某种编译器优化?只要编译并反汇编您的代码行,如果您非常想知道它到底是什么,您就可以得到您想要的 这是我在我的机器上得到的,以及我认为正在发生的事情:
u = (u++);
$cat evil.c
虚无罪恶{
int i=0;
i++=i+++++i;
}
$gcc evil.c-c-o evil.bin
$gdb.bin
(gdb)分解邪恶
函数邪恶的汇编程序代码转储:
0x00000000:推送%ebp
0x00000001:mov%esp,%ebp
0x00000003:子$0x10,%esp
0x00000006:movl$0x0,-0x4(%ebp)//i=0 i=0
0x0000000d:addl$0x1,-0x4(%ebp)//i++i=1
0x00000011:mov-0x4(%ebp),%eax//j=i=1 j=1
0x00000014:添加%eax,%eax//j+=j i=1 j=2
0x00000016:添加%eax,-0x4(%ebp)//i+=ji=3
0x00000019:addl$0x1,-0x4(%ebp)//i++i=4
0x0000001d:离开
i = i++ + ++i;
i = ++i + 1;
a[i++] = i;
i = i++ + ++i;
^ ^ ^
i = (i++);
^ ^
u = u++ + ++u;
^ ^ ^
u = (u++);
^ ^
v = v++ + ++v;
^ ^ ^
i = i++;
i = i++ + ++i;
while(*src++ = *dst++);
int k[] = {0,1,2,3,4,5,6,7,8,9,10};
int i = 0;
int num;
num = k[++i+k[++i]] + k[++i];
printf("%d", num);
num = k[i+1]+k[i+2] + k[i+3];
i += 3
i = i + 1
i++
i = i++
int i = 1;
i = i++;
il = ir++ // Note that suffix l and r are used for the sake of clarity.
// Both il and ir represents the same object.
temp = ir; // i = 1
ir = ir + 1; // i = 2 side effect by ++ before assignment
il = temp; // i = 1 result is 1
temp = ir; // i = 1
il = temp; // i = 1 side effect by assignment before ++
ir = ir + 1; // i = 2 result is 2
printf("%d %d\n", i, i++);
printf("%d %d\n", ++i, i++);
x = i++ + i++;
printf("%d %d\n", ++i, i++);
printf("%d %d\n", ++x, y++);
printf("%d %d\n", ++i, i++);
int i = 5;
int j;
j = (++i, i++); // No undefined behaviour here because the comma operator
// introduces a sequence point between '++i' and 'i++'
printf("i=%d j=%d\n",i, j); // prints: i=7 j=6
printf("%d %d\n", ++i, i++);
i = ++i + 1;
a[i++] = i;
i = i + 1;
a[i] = i;
% gcc plusplus.c -Wall -Werror -pedantic
plusplus.c: In function ‘main’:
plusplus.c:6:6: error: operation on ‘i’ may be undefined [-Werror=sequence-point]
i = i++ + ++i;
~~^~~~~~~~~~~
plusplus.c:6:6: error: operation on ‘i’ may be undefined [-Werror=sequence-point]
plusplus.c:10:6: error: operation on ‘i’ may be undefined [-Werror=sequence-point]
i = (i++);
~~^~~~~~~
plusplus.c:14:6: error: operation on ‘u’ may be undefined [-Werror=sequence-point]
u = u++ + ++u;
~~^~~~~~~~~~~
plusplus.c:14:6: error: operation on ‘u’ may be undefined [-Werror=sequence-point]
plusplus.c:18:6: error: operation on ‘u’ may be undefined [-Werror=sequence-point]
u = (u++);
~~^~~~~~~
plusplus.c:22:6: error: operation on ‘v’ may be undefined [-Werror=sequence-point]
v = v++ + ++v;
~~^~~~~~~~~~~
plusplus.c:22:6: error: operation on ‘v’ may be undefined [-Werror=sequence-point]
cc1: all warnings being treated as errors
j = (i ++, ++ i);
i += 2;
j = i;
int i = 0;
printf("%d %d\n", i++, ++i, i);
#include<stdio.h>
int main(int argc, char ** argv)
{
int i = 0;
i = i++ + ++i;
printf("%d\n", i); // 2
i = 1;
i = (i++);
printf("%d\n", i); //1
volatile int u = 0;
u = u++ + ++u;
printf("%d\n", u); // 2
u = 1;
u = (u++);
printf("%d\n", u); //1
register int v = 0;
v = v++ + ++v;
printf("%d\n", v); //2
#include<stdio.h>
int main(int argc, char ** argv)
{
int i = 0;
//i = i++ + ++i;
int r;
r=i;
i++;
++i;
r+=i;
i=r;
printf("%d\n", i); // 2
i = 1;
//i = (i++);
r=i;
i++;
i=r;
printf("%d\n", i); // 1
volatile int u = 0;
//u = u++ + ++u;
r=u;
u++;
++u;
r+=u;
u=r;
printf("%d\n", u); // 2
u = 1;
//u = (u++);
r=u;
u++;
u=r;
printf("%d\n", u); // 1
register int v = 0;
//v = v++ + ++v;
r=v;
v++;
++v;
r+=v;
v=r;
printf("%d\n", v); //2
}
#include<stdio.h>
int main(int argc, char ** argv)
{
int i = 0;
i = i++ + ++i;
printf("%d\n", i); // 3
i = 1;
i = (i++);
printf("%d\n", i); // 2
volatile int u = 0;
u = u++ + ++u;
printf("%d\n", u); // 3
u = 1;
u = (u++);
printf("%d\n", u); // 2
register int v = 0;
v = v++ + ++v;
printf("%d\n", v); // 3
}
#include<stdio.h>
int main(int argc, char ** argv)
{
int r;
int i = 0;
//i = i++ + ++i;
++i;
r = i + i;
i = r;
i++;
printf("%d\n", i); // 3
i = 1;
//i = (i++);
r = i;
i = r;
i++;
printf("%d\n", i); // 2
volatile int u = 0;
//u = u++ + ++u;
++u;
r = u + u;
u = r;
u++;
printf("%d\n", u); // 3
u = 1;
//u = (u++);
r = u;
u = r;
u++;
printf("%d\n", u); // 2
register int v = 0;
//v = v++ + ++v;
++v;
r = v + v;
v = r;
v++;
printf("%d\n", v); // 3
}
i=i++
tmp = i
i=i+1
i = tmp
tmp = i
i = tmp
i=i+1
int x = 5;
printf("%d %d %d\n", x, ++x, x++);
int x = 5;
x = x++ + ++x;
printf("%d\n", x);
printf("%d %d %d\n", x, ++x, x++);
x = x++ + ++x;
y = x++;
z = x++ + y++;
x = x + 1;
x = a[i++];
x = a[i++] + b[j++];
x[i++] = a[j++] + b[k++];
x = *p++;
x = *p++ + *q++;
x = x++;
x = x++ + ++x;
y = x + x++;
a[i] = i++;
a[i++] = i;
printf("%d %d %d\n", x, ++x, x++);
x = x++ + ++x;
y = x + x++;