c语言的比较运算符cmp,运算符,一种特殊的标识符----小话c语言(8)
[Mac-10.7.1 Lion Intel-based gcc 4.2.1]
Q: 可以把运算符看成特殊的标识符么?
A: 是的。例如 >= 运算符两个字符之间不能含有空格,这和标识符是类似的。
#include
int main()
{
1 > = 2;
return 0;
}
编译:
可以看到,> 和 = 符号中间的空格导致了编译器不能理解。
Q: 为什么会产生运算符结合性这个概念?
A: 结合性是在优先级相同的情况下才会进行结合性的判断得到表达式运算的真正的顺序。
Q: 赋值运算符怎么证明确实是右结合性?
A: 如下代码:
#include
int main()
{
int a, b, c;
a = b = c = 1;
return 0;
}
gcc -S operator.c得到汇编代码(部分):
movl$1, -20(%rbp)
movl-20(%rbp), %eax
movl%eax, -16(%rbp)
movl-16(%rbp), %eax
movl%eax, -12(%rbp)
-20(%rbp)即是表示c,-16(%rbp)表示b, -12(%rbp)表示a, 可以看到依次给c, b, a赋值,也就是体现了如下运算过程:
(a = (b = (c = 1)));
Q: 如下代码为什么结果始终不对?
#include
int main()
{
int a = 2;
if(a & 1 == 0)
printf("a & 1 == 0");
else
printf("a & 1 != 0");
return 0;
}
为什么一直输出“a & 1 != 0” ?
A: 这是因为==的优先级高于表示位与运算符&.所以a & 1 == 0的实际代码是a & (1 == 0),也就是a & 0, 当然结果不是预期了。
可以看下它的汇编(部分):
leaq L_.str(%rip), %rcx
movq %rcx, %rdi
callq _printf
L_.str:
.asciz "a & 1 != 0"
可以看到编译器进行了优化,直接输出L_.str字符串,根本没有进行运行时再次运算if表达式的值。在这种情况下,需要注意是否忽略了运算符优先级导致编译器直接优化了。
Q: sizeof到底是个运算符还是关键字?
A: 它应该被看成运算符。下面是c标准内容:
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
可以看出,sizeof被看成运算符。不过从另一个角度来说,关键字是从词法的角度进行分析的,运算符是从语法的角度分析的;如果从语法的角度来说,sizeof可以看成运算符,而从词法的角度来说,它不能看成关键字。不过依然不能把它当成变量来申明:
#include
int main()
{
int sizeof = 1;
return 0;
}
编译:
可以看到编译出错了。
Q: 都说sizeof在编译期就可以计算出数值,怎么证明?
A:
#include
int main()
{
int i = 1;
printf("%d\n", sizeof(i));
return 0;
}
它对应的汇编代码为(部分):
movl$4, %eax
xorb%cl, %cl
leaqL_.str(%rip), %rdx
movq%rdx, %rdi
movq%rax, %rsi
movb%cl, %al
callq_printf
笔者所在机器为x64架构,在x64上的参数传递,如果参数不超过6个,一般是先入寄存器,参数从左到右分别放入:rdi,rsi,rdx,rcx,r8,r9.
可以看到数字4直接放入了%eax, 最后用%eax的扩展寄存器%rax将数据放入%rsi; sizeof(i)的值在编译期就已经计算得到了4.
Q: sizeof后面可以跟表达式,下面的代码,为什么i++无效呢?
#include
int main()
{
int i = 1;
sizeof(i++);
printf("%d\n", i);
return 0;
}
运行结果:
A: 正因为sizeof是编译期求值的,所以如果它跟着表达式,那么表达式是不被计算的,只是根本表达式的类型得到它占用的空间。看下它的汇编:
movl$1, -12(%rbp)
movl-12(%rbp), %eax
xorb%cl, %cl
leaqL_.str(%rip), %rdx
movq%rdx, %rdi
movl%eax, %esi
movb%cl, %al
callq_printf
可以看到,调用printf函数之前直接将数据1当做参数输出,至于sizeof(i++)中的i++根本没有对应指令。
Q: 对于普通数组arr来说,sizeof(arr)可以确定arr的大小,那变长数组的sizeof如何计算呢?
A: 正因为是可变数组,所以sizeof计算它大小的过程将被推迟到运行时。
#include
#definePRINT_D(intValue)printf(#intValue" is %lu\n", (intValue));
size_t get_arr_len(int n)
{
char arr[n + 1];
return sizeof(arr);
}
int main()
{
PRINT_D(get_arr_len(1))
return 0;
}编译运行:
这里先介绍下VLA(变长数组),它是c99引入的特性,表示一个数组的长度不一定在编译期就可以确定,可以推迟到运行时。
我们先看下上面代码的汇编(部分):
0x0000000100000dcc :add $0x1,%edi
0x0000000100000dcf :mov %edi,%ecx
0x0000000100000dd1 :mov %rsp,%rdx
0x0000000100000dd4 :mov %rdx,-0x20(%rbp)
0x0000000100000dd8 :mov %rcx,-0x10(%rbp)
0x0000000100000ddc :movl $0x1,-0x24(%rbp)
0x0000000100000de3 :mov -0x20(%rbp),%rcx
0x0000000100000de7 :mov %rcx,%rsp
0x0000000100000dea :mov -0x10(%rbp),%rcx
0x0000000100000dee :mov (%rax),%rax
0x0000000100000df1 :mov -0x8(%rbp),%rdx
0x0000000100000df5 :cmp %rdx,%rax
0x0000000100000df8 :mov %rcx,-0x30(%rbp)
0x0000000100000dfc :jne 0x100000e08
可以看到,第一行执行了get_arr_len中n+1的操作,最后将得到的数据传递到%ecx中,最终在倒数第二行的地方将此数据传递出去;可以看出是在运行时计算数组大小的。
Q: 如下代码关于位运算符的操作为何最终结果和预期不符?
#include
int main()
{
unsigned char c = 0xfc;
unsigned int i = ~c;
printf("%#x\n",i);
return 0;
}
运行结果:
按照上面的代码,~c应该得到的是0x03, 那么结果应该是0x03, 怎么会是上面图片的结果呢?
A: 这是因为位运算是被提升到整形运算的。上面的变量c是无符号字符型,在进行~位运算时,是首先提升为整形,即为0x000000fc, 然后取反得到0xffffff03, 所以i得到的数值是这个。同理,如果c是char类型,提升为整形时为0xfffffffc,再取反得到的就是0x03.其实变量被提升有很多地方,比如short计算时也会提升为int再继续计算。
xichen
2012-5-15 11:04:55
c语言的比较运算符cmp,运算符,一种特殊的标识符----小话c语言(8)相关推荐
- C语言源文件名为什么无效,scanf函数,想说输入不容易!----小话c语言(3)
Q: 前面是关于输出的,给个关于输入的代码吧. A: 如下: #include int main() { int i; scanf("%d", &i); printf(&q ...
- C语言字符数组显示钻石,c++两种字符串赋值方式 并介绍 C语言下遍历目录文件的方式...
c++字符串声明:一种是声明字符数组并赋值,另一种是直接声明string类 #define _CRT_SECURE_NO_WARNINGS #include #include #include &qu ...
- 汇编和c只有一步之近----小话c语言(19)
作者:陈曦 日期:2012-6-8 10:50:13 环境:[Ubuntu 11.04 Intel-based x64 gcc4.5.2 CodeBlocks10.05 AT&T汇编 ...
- c语言basic解释器,要理解解释器,做一个小解释器----小话c语言(20)
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 } list->tail->next = obj; list->tail = obj; return obj; } void cc_ar ...
- c语言共有几种运算符_【填空题】C语言一共有 ()个关键字,()中控制语句,()种运算符...
[填空题]C语言一共有 ()个关键字,()中控制语句,()种运算符 更多相关问题 [填空题] 对煤进行工业分析的目的,是为了判断煤的(). [填空题] 钛的比重是不锈钢的一半,抗腐蚀性是不锈钢的(). ...
- sizeof是c语言的一种运算符,C语言位运算和sizeof运算符详解
位运算和sizeof运算符 C语言中提供了一些运算符可以直接操作整数的位,称为位运算,因此位运算中的操作数都必须是整型的.位运算的效率是比较高的,而且位运算运用好的话会达到意想不到的效果.位运算主要有 ...
- python语言有哪些类型的运算符_python(4)-变量 数据类型和运算符
第二章:变量.数据类型.运算符 思考:怎么理解变量和内存? 变量:就等同于上面图中的age name hobby 内存:存储位置里所装的内容 18 张三 打球 变量一定是存在某个地址,可以从变量名找到 ...
- c语音异或运算符_C语言中的按位异或运算符有什么用处?
原标题:C语言中的按位异或运算符有什么用处? 想知道C语言中的按位异.运算符有什么用处,首先C语言中^为按位异或运算符,若两个二进制位相同,则结果为0,不同为1 例: #include "s ...
- C语言自加自减运算符(++i / i++) - C语言零基础入门教程
目录 一.C 语言自加++ / 自减 – 运算符简介 1.前 ++ 后 ++ 的区别 2.前–后-- 的区别 二.C 语言自加++/自减–运算符实战 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : ...
最新文章
- DPI — 深度数据报文解析
- 【CF 应用开发大赛】JEECG 基于代码生成器J2EE智能开发框架
- JAVA后端面试100 QA之第一篇
- OpenGL于MFC使用汇总(三)——离屏渲染
- [Usaco2008 Mar]River Crossing渡河问题
- 传智播客 刘意_2015年Java基础视频-深入浅出精华版 笔记(day01~day10)(2015年11月17日20:47:22)...
- Python基础【day03】:文件操作(七)
- php--PDO操作数据库
- 计算机考研高等代数,福大考研经验贴:我的数学考研之路(数学分析和高等代数)...
- 20款优秀的基于浏览器的在线代码编辑器
- dex2jar .\classes.dex - .\classes-dex2jar.jar com.googlecode.d2j.DexException: not support version
- adb命令连接设备出现Offline
- 软件设计原则之里氏替换原则、依赖倒置原则
- 2021中国软件和信息技术服务竞争力百强
- EXCEL必备工具箱(EXCELtool)官方免费版V17.0 | 超级excel插件工具箱下载 | 完整的excel办公自动化工具箱
- 数字图像处理 图像变换
- CSS中min-height、min-width、max-width、max-height的理解及优先级问题
- FishHook钩子库开发日志
- 计算机应用国防教育方向,计算机应用专业图形图像方向人才培养方案.DOC
- Docker compose file 中文参考文档