user-0 提问: c和指针 操作符

回复:
user: user-1
content: if(a >= 1 && a<= 10) 00F829D5  cmp         dword ptr [a],1   00F829D9  jl          main+48h (0F829F8h)   00F829DB  cmp         dword ptr [a],0Ah   00F829DF  jg          main+48h (0F829F8h)   当然就是顺序了 	if(1 <= a <= 10) 000A29D5  cmp         dword ptr [a],1   000A29D9  jl          main+37h (0A29E7h)   000A29DB  mov         dword ptr [ebp-0D0h],1   000A29E5  jmp         main+41h (0A29F1h)   000A29E7  mov         dword ptr [ebp-0D0h],0   000A29F1  cmp         dword ptr [ebp-0D0h],0Ah   000A29F8  jg          main+61h (0A2A11h)

user: user-2
content: 什么书？不一定吧！

user: user-3
content: 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！

user: user-0
content: 比如if(x+y+1>0)在K&R C中程序员无法预测编译器按哪种顺序对这个表达式求值 书上明确写了ANSI C不允许这样做。

user: user-0
content: 对不起我搞错了，那是K&R C而不是现在的ANSI C哎呀其实我也不是很清楚，分就随便给吧

user: user-0
content: 《c和指针》中文版P84下半部分

user: user-4
content: 引用 16 楼 u011779875 的回复:我说书错 是因为 按照C标准的要求  1 + 2 + 3 第一个 + 先和操作数结合 (1 + 2) + 3 i = c = d 右结合 最右边的 = 先和操作数结合 i = (c = d) 只能这么解释 没有二义性 没有第二种可能  如果 把 1 + 2 + 3解释为 1 + 2 + 3 那么 + 是右结合  这是这个表达式巧合 求值结果一样  如果是 1 - 2 + 3 根据右结合 变成 1 - (2 + 3) 那就大错特错了你的理解是有偏差的  你的所谓的结合性 是给程序员规定的 而我们讨论的是编译器优化的问题   正如 1+2+3，编译器可以先计算2+3，再计算1+（2+3）  注意红色的字，那是可以，而不是一定或者必然或者肯定....   编译器的实现 是和它表明告诉人们的标准不一定是重合的  你有点理解偏了  其实书上的意思是在特定的情况满足下 编辑器会进行适当的优化 而这种优化是你所不能理解的 [/quote] 也许 先计算 2 不好理解  fooA()+fooB()+fooC() 这个表达式 函数调用的顺序 可能 先调用fooB 在调用fooC 以上

user: user-1
content: gcc -E test.c -o test.i  引用 15 楼 lin5161678 的回复:[quote=引用 12 楼 u011779875 的回复:] 预处理的实现是编译器的一部分 不是编译器解决的吗我一直说是编译器解决的  是你说预处理解决的  就算预处理是编译器的一部分  那也是预处理完成之后 编译器的其他部分处理 1+2+3 [/quote]gcc -E test.c -o test.i 可以输出test.i文件中存放着test.c经预处理之后的代码。打开test.i文件，看一看，就明白了。 如果我错了 那我错了 我讨论那个没什么意义 试一试就知道了 我感觉我错误的可能性是比较大的  你赢了

user: user-4
content: 引用 16 楼 u011779875 的回复:你的理解是有偏差的  你的所谓的结合性 是给程序员规定的 而我们讨论的是编译器优化的问题   正如 1+2+3，编译器可以先计算2+3，再计算1+（2+3）  注意红色的字，那是可以，而不是一定或者必然或者肯定....   编译器的实现 是和它表明告诉人们的标准不一定是重合的  你有点理解偏了  其实书上的意思是在特定的情况满足下 编辑器会进行适当的优化 而这种优化是你所不能理解的 编译器优化没那么神秘  这里只是 可以先计算 2 也可以先计算 3 但是 绝对不会 先计算 2+3  因为 对于这表达式的分析 就不会出现 2+3 这个算子 [子表达式] 不存在的东西 不可能对他进行求值的

user: user-1
content: 引用 13 楼 lin5161678 的回复:[quote=引用 12 楼 u011779875 的回复:] 这样就可以知道是在哪个阶段处理的 也许是我记错了或许我还没错呢  但是你也不能说人家书错了啊 我说书错 是因为 按照C标准的要求  1 + 2 + 3 第一个 + 先和操作数结合 (1 + 2) + 3 i = c = d 右结合 最右边的 = 先和操作数结合 i = (c = d) 只能这么解释 没有二义性 没有第二种可能  如果 把 1 + 2 + 3解释为 1 + 2 + 3 那么 + 是右结合  这是这个表达式巧合 求值结果一样  如果是 1 - 2 + 3 根据右结合 变成 1 - (2 + 3) 那就大错特错了  [/quote]你的理解是有偏差的  你的所谓的结合性 是给程序员规定的 而我们讨论的是编译器优化的问题   正如 1+2+3，编译器可以先计算2+3，再计算1+（2+3）  注意红色的字，那是可以，而不是一定或者必然或者肯定....   编译器的实现 是和它表明告诉人们的标准不一定是重合的  你有点理解偏了  其实书上的意思是在特定的情况满足下 编辑器会进行适当的优化 而这种优化是你所不能理解的

user: user-4
content: 引用 12 楼 u011779875 的回复:预处理的实现是编译器的一部分 不是编译器解决的吗我一直说是编译器解决的  是你说预处理解决的  就算预处理是编译器的一部分  那也是预处理完成之后 编译器的其他部分处理 1+2+3

user: user-4
content: 如果 把 1 + 2 + 3解释为 1 + (2 + 3) 那么 + 是右结合

user: user-4
content: 引用 12 楼 u011779875 的回复:这样就可以知道是在哪个阶段处理的 也许是我记错了或许我还没错呢  但是你也不能说人家书错了啊 我说书错 是因为 按照C标准的要求  1 + 2 + 3 第一个 + 先和操作数结合 (1 + 2) + 3 i = c = d 右结合 最右边的 = 先和操作数结合 i = (c = d) 只能这么解释 没有二义性 没有第二种可能  如果 把 1 + 2 + 3解释为 1 + 2 + 3 那么 + 是右结合  这是这个表达式巧合 求值结果一样  如果是 1 - 2 + 3 根据右结合 变成 1 - (2 + 3) 那就大错特错了

user: user-1
content: 引用 11 楼 lin5161678 的回复:[quote=引用 9 楼 u011779875 的回复:] int a; a = 1 + 2 + 3; 011313BE  mov         dword ptr [a],6    你敢说这不是预处理做的 那个6是什么  你敢说不是编译器在预处理阶段做的 虽然我才毕业4个月 但是人总会犯错的 我喜欢承认并解决错误 难道你真的成为了亚里士多德 我看不是吧    你拿出证据 无证据不要瞎说 少年 1+2+3是 编译期常量 编译器把他处理为 6  不是预处理 预处理做的 #include #if 宏展开 处理折行符 处理注释这些事情 1+2+3 原原本本的提交给编译器  你看到的是编译器处理的结果 无法说明是预处理器处理的结果 明白吗? [/quote]预处理的实现是编译器的一部分 不是编译器解决的吗 我记得在linux下 直接打gcc -E test.c -o test.i  这样就可以知道是在哪个阶段处理的 也许是我记错了或许我还没错呢  但是你也不能说人家书错了啊

user: user-4
content: 引用 9 楼 u011779875 的回复:int a; a = 1 + 2 + 3; 011313BE  mov         dword ptr [a],6    你敢说这不是预处理做的 那个6是什么  你敢说不是编译器在预处理阶段做的 虽然我才毕业4个月 但是人总会犯错的 我喜欢承认并解决错误 难道你真的成为了亚里士多德 我看不是吧    你拿出证据 无证据不要瞎说 少年 1+2+3是 编译期常量 编译器把他处理为 6  不是预处理 预处理做的 #include #if 宏展开 处理折行符 处理注释这些事情 1+2+3 原原本本的提交给编译器  你看到的是编译器处理的结果 无法说明是预处理器处理的结果 明白吗?

user: user-5
content: 看书上说如果有表达式1+2+3，编译器可以先计算2+3，再计算1+（2+3）  注意红色的字，那是可以，而不是一定或者必然或者肯定....

user: user-1
content: 引用 7 楼 lin5161678 的回复:[quote=引用 5 楼 u011779875 的回复:] 人家书我感觉没有错  只不过人家的意思是 1+2+3 是写到程序里的  编译器如何处理 你就不得而知了例如int a = 1 + 2+ 3; 它的处理过程是在宏替换就处理完的 你没写过编译器 你怎么知道不可以呢先算 1+（2+3） 有点常识 好不好 1+2+3 和预处理没什么关系 然后 1+2+3 处理为 (1+2)+3是由 优先级结合性决定的  编译器的实现是必须符合这个要求的[/quote] int a; a = 1 + 2 + 3; 011313BE  mov         dword ptr [a],6    你敢说这不是预处理做的 那个6是什么  你敢说不是编译器在预处理阶段做的 虽然我才毕业4个月 但是人总会犯错的 我喜欢承认并解决错误 难道你真的成为了亚里士多德 我看不是吧    你拿出证据 无证据不要瞎说

user: user-4
content: 引用 6 楼 u012453424 的回复:《c和指针》上说的 第几版第几页第几章第几段

user: user-4
content: 引用 5 楼 u011779875 的回复:人家书我感觉没有错  只不过人家的意思是 1+2+3 是写到程序里的  编译器如何处理 你就不得而知了例如int a = 1 + 2+ 3; 它的处理过程是在宏替换就处理完的 你没写过编译器 你怎么知道不可以呢先算 1+（2+3） 有点常识 好不好 1+2+3 和预处理没什么关系 然后 1+2+3 处理为 (1+2)+3是由 优先级结合性决定的  编译器的实现是必须符合这个要求的

user: user-0
content: 引用 4 楼 lin5161678 的回复:引用看书上说如果有表达式1+2+3，编译器可以先计算2+3，再计算1+（2+3） 什么书 错这么离谱 1+2+3 必然是 (1+2)+3 没有第二种可能   书说错 《c和指针》上说的