一、逻辑运算符使用分析
1.短路规则:
---||从左向右开始计算,当遇到条件为真的条件时停止计算,整个表达式为真,所有条件为假时表达式才假。
---&&从左向右开始计算,当遇到条件为假时停止计算,整个表达式为假,所有条件为真时表达式才为真。
Example:
int g = 0;
int f()
{
return g++;
}
int main()
{
int i = 0;
int j = 0;
if(++i > 0 || ++j > 0){
printf("%d\n",i);
printf("%d\n",j);
}
if( f() && f() ){
printf("%d\n",g);
}
printf("%d\n",g);
return 0;
}
2.C语言中逻辑符“ !”只认得0,只知道见了0就返回1.因此当其作用的值不是0时,其结果为0.
二、位运算符分析
1.左移和右移注意点
---左移运算符<<将运算符数的二进制位左移。规则:高位丢弃,低位补0
---右移运算符>>将运算符数的二进制位右移。规则:高位补符号位,低位丢弃
---左移n位相当于乘以2的n次方,但效率比数学运算符高
---右移n为相当于除以2的n次方,但效率比数学运算符高
Example:
1 #include
2
3 #define SWAP(a,b)\
4 { \
5 int temp = a;\
6 a = b; \
7 b = temp; \
8 }
9 #define SWAP1(a,b)\
10 { \
11 a = a + b;\
12 b = a - b;\
13 a = a - b; \
14 }
15 #define SWAP2(a,b)\
16 { \
17 a = a ^ b; \
18 b = a ^ b; \
19 a = a ^ b; \
20 }
21
22 int main()
23 {
24 int a = 1;
25 int b = 2;
26 // SWAP1(a,b);
27 SWAP2(a,b);
28 printf("a = %d,b = %d\n",a,b);
29 return 0;
30 }
Example:有一个数列,其中的自然数都是以偶数的形式出现,只有一个自然数出现的次数为奇数次。编程找出这个自然数。
1 #include
2
3 #define DIM(a) (sizeof(a)/sizeof(*a))
4
5 int main()
6 {
7 int a[] = {2,3,5,7,2,2,2,5,3,7,1,1,1};
8 int find = 0;
9 int i = 0;
10 for(i = 0; i < DIM(a); i++){
11 find = find ^ a[i];
12 }
13 printf("find = %d\n",find);
14 return 0;
15 }
三、类型转换分析
1.C语言隐式类型转换
---算术运算式中,低类型转换为高类型
---赋值表达式中,表达式的值转换为左边变量的类型
---函数调用时,实参转换为形参的类型
---函数返回时,return表达式转换为返回值类型
char } int -> unsigned int -> long -> unsigned long ->double <- float
short}
Example:
1 #include
2
3 int main()
4 {
5 int i = -2;
6 unsigned int j = 1;
7
8 if((i + j) >= 0){
9 printf("i + j >= 0\n");
10 }else{
11 printf("i + j < 0\n");
12 }
13
14 printf("i + j = %d\n", i + j);
15 printf("i + j = %0X\n",i + j);
16 return 0;
17 }
Result:
mq@ubuntu:~/program/cpro$ ./a.out
i + j >= 0
i + j = -1
四、编译过程
1.预编译
处理所有的注释,以空格代替
将所有的#define删除,并且展开所有的宏定义
处理条件编译指令#if, #ifdef, #elif, #else, #endif
处理#include,展开被包含的文件
保留编译器需要使用的#pragma指令
预处理指令:gcc -E file.c -o file.i
2.编译
对预处理文件进行一系列词法分析,语法分析和语义分析
词法分析主要分析关键字,标示符,立即数等是否合法
语法分析主要分析表达式是否遵循语法规则
语义分析在语法分析的基础上进一步分析表达式是否合法
分析结束后进行代码优化生成相应的汇编代码文件
编译指令: gcc -S file.c -o file.s
3.汇编
汇编器将汇编代码转变为机器可以执行的指令
每个汇编语句几乎都对应一条机器指令
汇编指令:gcc -c file.s -o file.o
五.宏定义与使用分析
#define定义宏常量可以出现在代码的任何地方
#define从本行开始,之后的代码都可以使用这个宏常量
#define表达式给有函数调用的假象,却不是函数
#define表达式可以比函数更强大
#define表达式比函数更容易出错
2.宏表达式与函数的对比
宏表达式在预编译期被处理,编译器不知道宏表达式的存在
宏表达式用“实参”完全替代形参,不进行任何运算
宏表达式没有任何的“调用”开销
宏表达式中不能出现递归定义
3.强大的内置宏
__FILE__ 被编译的文件名
__LINE__ 当前行号
__DATE__ 编译时的日期
__TIME__ 编译时的时间
__STDC__ 编译器是否遵循标准C规范
Example:定义日志宏
1 #include
2 #include
3
4 #define LOG(s){ \
5 time_t t; \
6 struct tm* ti; \
7 time(&t); \
8 ti = localtime(&t); \
9 printf("%s[%s:%d]%s\n",asctime(ti),__FILE__,__LINE__,s); \
10 }
11
12 void f()
13 {
14 LOG("Enter f()...");
15 LOG("Exit f()...");
16 }
17
18 int main()
19 {
20 LOG("Enter main...");
21 f();
22 LOG("Exit main...");
23
24 return 0;
25 }
阅读(1147) | 评论(0) | 转发(0) |