问个自增/自减与赋值运算符优先级关系的问题

C、C++和Java语言
回复
头像
灰色小狼
帖子: 4573
注册时间: 2008-12-06 10:38
系统: Arch
送出感谢: 21 次
接收感谢: 30 次

问个自增/自减与赋值运算符优先级关系的问题

#1

帖子 灰色小狼 » 2010-11-05 12:02

先来段代码:

代码: 全选

void strcpy(char *s,char *t)
{
    while (*s++ = *t++)
        ;
}
[/color][/b]

啥时候我也写的出这么漂亮的代码额 :em03

我看到的关于while (*s++ = *t++)一句大家比较认可的解释是:
(1)*t 的赋值给 *s
(2)判断 *s 是否为真。如果为假,则跳出循环;否则继续执行第(3)步。因为字符串是以\0结尾的,遇到\0的时候,也就是*s为假,就跳出了字符串拷贝。
(3)s 和 t 加 1,指向下一个地址,准备拷贝下一个字符。
我扩充一下,不知道对不对:
(1) 取t和s的值t'和s'到内存的某个位置;
(2) 取出*t' 和*s';
(3) *t' 的赋值给 *s';
(4) 判断 *s' 是否为真。如果为假,则跳出循环,否则继续执行(5)步;
(5) s 和 t 加 1。
我的问题是:
1. 根据运算符优先级,后自增运算符的优先级比赋值高,所以顺序是(1)(2)(5)(3)(4);
2. 根据运算符优先级,后自增运算符的优先级比提领(*)高,所以取出t' 和s' 后应该先对t和s进行自增,然后在取*t' 和*s',
所以正确的顺序应该是(1)(5)(2)(3)(4)。
是这样的吗?如果不是,为什么?

最后弱弱地说一句:我是小菜…… :em03
头像
linjiework
帖子: 240
注册时间: 2009-07-07 19:52
送出感谢: 0
接收感谢: 0

Re: 问个自增/自减与赋值运算符优先级关系的问题

#2

帖子 linjiework » 2010-11-05 14:58

这段代码也算漂亮?

要是谁在工作中这么写,那他离被开除不远了。
阿呆 : 天下第一呆!
头像
灰色小狼
帖子: 4573
注册时间: 2008-12-06 10:38
系统: Arch
送出感谢: 21 次
接收感谢: 30 次

Re: 问个自增/自减与赋值运算符优先级关系的问题

#3

帖子 灰色小狼 » 2010-11-05 15:51

额……看来还没工作就要面临被开出了……
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
送出感谢: 0
接收感谢: 7 次
联系:

Re: 问个自增/自减与赋值运算符优先级关系的问题

#4

帖子 BigSnake.NET » 2010-11-05 17:12

linjiework 写了:这段代码也算漂亮?

要是谁在工作中这么写,那他离被开除不远了。
其实从可读性来说没什么问题

C的惯用法吧 ..
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
头像
灰色小狼
帖子: 4573
注册时间: 2008-12-06 10:38
系统: Arch
送出感谢: 21 次
接收感谢: 30 次

Re: 问个自增/自减与赋值运算符优先级关系的问题

#5

帖子 灰色小狼 » 2010-11-05 19:54

事实证明我的想法是错误的,这是一个简单的测试程序:

代码: 全选

#include <stdio.h>

void copy(char *, char *);

int main()
{
	char t[] = "Hello world!";
	char s[] = "";
	copy(s, t);
	printf("%s\n", s);
}

void copy(char *s,char *t)
{
	while (*s++ = *t++)
		;
}
[/color]

这是它的汇编代码:

代码: 全选

	.file	"strcopy.c"
	.section	.rodata
.LC0:
	.string	""
	.text
.globl main
	.type	main, @function
main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	subl	$48, %esp
	movl	%gs:20, %eax
	movl	%eax, 44(%esp)
	xorl	%eax, %eax
	movl	$1819043144, 31(%esp)
	movl	$1870078063, 35(%esp)
	movl	$560229490, 39(%esp)
	movb	$0, 43(%esp)
	movzbl	.LC0, %eax
	movb	%al, 30(%esp)
	leal	31(%esp), %eax
	movl	%eax, 4(%esp)
	leal	30(%esp), %eax
	movl	%eax, (%esp)
	call	copy
	leal	30(%esp), %eax
	movl	%eax, (%esp)
	call	puts
	movl	44(%esp), %edx
	xorl	%gs:20, %edx
	je	.L3
	call	__stack_chk_fail
.L3:
	leave
	ret
	.size	main, .-main
.globl copy
	.type	copy, @function
copy:
	pushl	%ebp
	movl	%esp, %ebp
.L5:
	movl	12(%ebp), %eax
	movzbl	(%eax), %edx
	movl	8(%ebp), %eax
	movb	%dl, (%eax)
	movl	8(%ebp), %eax
	movzbl	(%eax), %eax
	testb	%al, %al
	setne	%al
	addl	$1, 8(%ebp)
	addl	$1, 12(%ebp)
	testb	%al, %al
	jne	.L5
	popl	%ebp
	ret
	.size	copy, .-copy
	.ident	"GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
	.section	.note.GNU-stack,"",@progbits
[/color]

那么现在的问题就是:后自增比赋值的优先级要高,而表面上看上去自增却发生在赋值之后,我认为我的说法可以解释这个问题(赋值掉取的是原变量在内存中的一个副本,而变量本身已经增加了),但从汇编的代码不支持这个说法,那么怎么解释这里的优先级问题呢?哪位高手能不能举个例子展示一下后自增比赋值的优先级要高呢?
头像
HuntXu
论坛版主
帖子: 5778
注册时间: 2007-09-29 3:09
送出感谢: 0
接收感谢: 6 次

Re: 问个自增/自减与赋值运算符优先级关系的问题

#6

帖子 HuntXu » 2010-11-05 20:30

后缀运算的表达式值是不变的...
HUNT Unfortunately No Talent...
头像
灰色小狼
帖子: 4573
注册时间: 2008-12-06 10:38
系统: Arch
送出感谢: 21 次
接收感谢: 30 次

Re: 问个自增/自减与赋值运算符优先级关系的问题

#7

帖子 灰色小狼 » 2010-11-05 20:46

HuntXu 写了:后缀运算的表达式值是不变的...
额……不明白 :em06
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
送出感谢: 0
接收感谢: 7 次
联系:

Re: 问个自增/自减与赋值运算符优先级关系的问题

#8

帖子 BigSnake.NET » 2010-11-05 20:49

灰色小狼 写了:事实证明我的想法是错误的,这是一个简单的测试程序:

代码: 全选

#include <stdio.h>

void copy(char *, char *);

int main()
{
	char t[] = "Hello world!";
	char s[] = "";
	copy(s, t);
	printf("%s\n", s);
}

void copy(char *s,char *t)
{
	while (*s++ = *t++)
		;
}
[/color]

这是它的汇编代码:

代码: 全选

	.file	"strcopy.c"
	.section	.rodata
.LC0:
	.string	""
	.text
.globl main
	.type	main, @function
main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	subl	$48, %esp
	movl	%gs:20, %eax
	movl	%eax, 44(%esp)
	xorl	%eax, %eax
	movl	$1819043144, 31(%esp)
	movl	$1870078063, 35(%esp)
	movl	$560229490, 39(%esp)
	movb	$0, 43(%esp)
	movzbl	.LC0, %eax
	movb	%al, 30(%esp)
	leal	31(%esp), %eax
	movl	%eax, 4(%esp)
	leal	30(%esp), %eax
	movl	%eax, (%esp)
	call	copy
	leal	30(%esp), %eax
	movl	%eax, (%esp)
	call	puts
	movl	44(%esp), %edx
	xorl	%gs:20, %edx
	je	.L3
	call	__stack_chk_fail
.L3:
	leave
	ret
	.size	main, .-main
.globl copy
	.type	copy, @function
copy:
	pushl	%ebp
	movl	%esp, %ebp
.L5:
	movl	12(%ebp), %eax
	movzbl	(%eax), %edx
	movl	8(%ebp), %eax
	movb	%dl, (%eax)
	movl	8(%ebp), %eax
	movzbl	(%eax), %eax
	testb	%al, %al
	setne	%al
	addl	$1, 8(%ebp)
	addl	$1, 12(%ebp)
	testb	%al, %al
	jne	.L5
	popl	%ebp
	ret
	.size	copy, .-copy
	.ident	"GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
	.section	.note.GNU-stack,"",@progbits
[/color]

那么现在的问题就是:后自增比赋值的优先级要高,而表面上看上去自增却发生在赋值之后,我认为我的说法可以解释这个问题(赋值掉取的是原变量在内存中的一个副本,而变量本身已经增加了),但从汇编的代码不支持这个说法,那么怎么解释这里的优先级问题呢?哪位高手能不能举个例子展示一下后自增比赋值的优先级要高呢?
这样说吧
1. 两个 * 所解引用的都是 ++ 前的指针
2. 所以那个赋值相当于 *s = *t
3. 其他的顺序未定义, 但是所有副作用(++, 赋值) 都在那个分号之前完成
4. 所谓的优先级不是指运算顺序,是指结合性 例如 a = b++ 是理解成 a = (b++) 而不是 (a = b) ++, 那个 b 的自增不保证在赋值之后执行, 但是赋值给 a 的一定是 b 自增之前的值
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
送出感谢: 0
接收感谢: 7 次
联系:

Re: 问个自增/自减与赋值运算符优先级关系的问题

#9

帖子 BigSnake.NET » 2010-11-05 20:52

补充语句, 如果是
* s = * s++;
那就是脑残代码了,因为你不知道那个 ++ 在什么时候发生,所以不知道左边取出来的 s 是自增前还是自增后
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
头像
灰色小狼
帖子: 4573
注册时间: 2008-12-06 10:38
系统: Arch
送出感谢: 21 次
接收感谢: 30 次

Re: 问个自增/自减与赋值运算符优先级关系的问题

#10

帖子 灰色小狼 » 2010-11-05 21:13

BigSnake.NET 写了: 4. 所谓的优先级不是指运算顺序,是指结合性 例如 a = b++ 是理解成 a = (b++) 而不是 (a = b) ++, 那个 b 的自增不保证在赋值之后执行, 但是赋值给 a 的一定是 b 自增之前的值
醍醐灌顶 :em11 多谢
头像
灰色小狼
帖子: 4573
注册时间: 2008-12-06 10:38
系统: Arch
送出感谢: 21 次
接收感谢: 30 次

Re: 问个自增/自减与赋值运算符优先级关系的问题

#11

帖子 灰色小狼 » 2010-11-05 21:24

看来果然还是我太菜了……基本的概念都没搞懂 :em19
回复

回到 “C/C++/Java”