首页 > 代码库 > 2017年1月15日 11:20:59杂项

2017年1月15日 11:20:59杂项

位操作

位操作的必要性:通过串口或并口与其他器件相连

&按位与

|按位或

^按位异或:两位相异时为1,相同时为0.

上述三个操作满足结合律和交换率。

 

左移运算符:<<将要运算的二进制位左移

规则:高位丢弃,低位补0.

使用格式:

int a = 1<<1;

a = 2;

右移运算符:>>讲要运算的二进制右移

规则:高位补符号位,地位丢弃。

符号位:若为正数则符号位是0,负数符号位为1

 

小技巧:

左移n位相当于乘以2n次方,但效率比数学运算高。

右移n位相当于除以2n次方,但效率比数学运算高。

 

 

防错准则:

避免位操作运算符,逻辑运算符和数学运算符同出现在一个表达式中

当位运算符,逻辑运算符和数学运算符需要同时参与运算时,尽量使用括号()来表达计算次序。

嵌入式比较讲究效率!

 

加减法的优先级高于左移和右移。

 

交换两个变量:利用#define\代码块替换

 

#define SWAP1(a,b) \

{   \

int temp = a; \

a = b; \

b = temp; \

} \

 

#define SWAP2(a,b) \

{   \

a = a + b; \

b = a - b ; \

a = a - b ; \

} \

问题:如果a很大,b很大,a+b的值可能会使a溢出。

 

#define SWAP3(a,b) \

{   \

a = a ^ b; \

b = a ^ b ; \

a = a ^ b ; \

} \

 

位运算符的效率比加减高得多,整数交换建议用第三种方法。

 

 

 

 

某个面试题:

有一个数列,其中的自然数都是以偶数的形式存在,只有一个自然数出现的次数为奇数次,找出这个数。

 

贪心法——++--表达式阅读技巧

1.编译器处理的每个符号应该尽可能多的包含字符

2.编译器从左像右一个一个尽可能多的读入字符

3.当即将读入的字符不可能和已读入的字符组成合法符号为止。

 

 

程序编译的四个步骤:

.c.h文件经过预处理cpp产生.i文件,再经过编译器gcc,产生.s文件,经过汇编器as产生.o文件,.o.a文件经过链接器产生.out文件。

 

预编译阶段:

处理掉所有注释,用空格代替。

#define删除,展开所有的宏

处理条件编译指令#if,#ifdef,#elif,#else,#endif.

处理#include,展开被包含的文件

保留编译器需要使用的#pragma指令

预处理指令:gcc-E file.c-o hello.i

 

编译阶段:

对预处理文件进行一系列的词法分析,语法分析和语义分析

词法分析:关键字,标示符,立即数等

语法分析:表达式是否遵循语法会泽

语义分析:在语法分析的基础上进一步分析

生成.i文件

 

分析结束后,进行代码优化生成相应的汇编代码文件

编译指令: gcc-S file.c -o hello.s

生成.s文件。

 

链接器:将.o文件和库文件装载在一起,生成最终可执行文件。

 

与源代码密切相关的,预处理,编译,汇编。

 

链接器

作用:把各个模块之间相互引用的部分处理好,使个个模块正确衔接。

 

#define定义宏常量可以出现在代码的任何地方

#define从本行开始,之后的代码都可以使用这个宏常量。

#define 别名 原内容

#define 路径用法:

#define  PATH_1  D:\XYZ\test.c

 

#define表达式有函数调用的假象,却不是

#define表达式可以比函数更强大

#define表达式比函数更容易出错

 

 

printf(“%d\n”,((i++<j)  ? (i++)  :  (j)));

 

 

宏表达式在预编译期被处理,编译器不知道宏表达式的存在

宏表达式用“实参”完全替代形参,不进行任何计算。

宏表达式没有任何“调用”开销

宏表达式不能出现递归定义

 

宏定义的范围

#define   X    256

//以下可使用,直到#undef X

#undef   X

 

强大的内置宏

含义 示例

_FILE_   被编译的文件名 file1.c

_LINE_ 当前行数 25

_DATE_ 编译时日期 Jan312012

_TIME_ 编译时时间 170101

_STDC_ 是否遵循标准C规范 1

 

 

 

定义日志宏

如果用函数来写日志:

void log(char* s)

{

printf(“%s %d %s\n”,_FILE_,_LINE_,s); //

}

 

如果在文件中不停调用这个函数,会发现显示的第二个数据一直为函数定义时的行数。

因为要调用这个函数时,需要跳回函数执行,这样只会输出定义函数时的行数。

这时需要用到宏定义

 

#define LOG(s) \printf(“%s %d %s\n”,_FILE_,_LINE_,s);

 

这几个信息不够,还需要加上时间

先包含时间头文件,#include “time.h”

void f()

{

time_t t;

struct tm* ti;

time(&t);

ti = localtiome(&t);

printf(“%s %d %s”,asctime(ti),_LINE_,_FILE_,s);

}

如何将这个函数加到宏定义

 

#define LOG(s)  do{ \

time_t t; \

struct tm* ti; \

time(&t); \

ti = localtime(&t); \

printf(“%s [%s %d],%s”,asctime(ti),_FILE_,_LINE_,s); \

}while(0);

牛叉的续行符!

 

课后思考:

#define  f   (x)      ((x)-1)

宏代表什么意思?对空格敏感么?宏“调用”对空格敏感么

 

 

  

 

2017年1月15日 11:20:59杂项