技术积累
1、时间复杂度和空间复杂度
时间复杂度:
指执行当前算法所消耗的时间
空间复杂度:
指当前当前算法需要占用多少的内存
2、Struct
1)字节对齐
自然对齐(即默认对齐方式):是指按结构体的成员中size最大的成员对齐。
指定对齐:
使用伪指令 #pragma pack (n) ,编译器将按照n个字节对齐
使用伪指令#pragma pack () , 取消自定义字节对齐方式
(注意:如果#pragma pack (n)中指定的n大于结构体中最大成员的size,则不起作用,结构体仍然按照size最大的成员进行对齐。)
2)与Class 对比
-
- Struct 中成员变量默认为public ,而Class 中成员变量默认为private
- Struct 可以在定义时直接以{ }的形式对齐成员变量进行赋值
3、Extern “C”
1)被Extern “C” 修饰的变量和函数是按照C语言方式编译和连接的。
2)如果在模块A中函数声明了foo为extern “C”类型,而模块B中包含的是extern int foo(int x,int y),则模块B找不到模块A中的函数。
3)在C中引用C++中的函数和变量时,C++的头文件需添加extern “C”,但是在C语言中不能直接引用声明了extern C的该头文件。
4、C高效编程技巧
1)以空间换时间
使用宏函数代替函数:
==========================
#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
#define bmMCDR2_ADDRESS BIT_MASK
(MCDR2_ADDRESS)
#define BIT_MASK(_bf)(((1U<<(bw##_bf))-1)<<
(bs##_bf)
#define SET_BITS(_dst,_bf,_val)\
((_dst)=((_dst)&~(BIT_MASK(_bf)))I
(((_val)<<(bs##_bf))&(BIT_MASK(_bf))))
SET_BITS(MCDR2,MCDR2_ADDRESS,RegisterNumb
er);
==========================
函数和宏函数的区别在于:宏函数占用了大量的空间,而函数占用时间。函数调用是要使用系统的栈来保存数据,同时CPU也要在函数调用时保存和恢复当前的现场,进行压栈和弹栈操作。
2)数学方法解决问题
============================
I=(100*(1+100))/2
============================
3)使用位操作
使用位操作,减少除法和取模的运算
============================
I=257>>3;
============================
4)嵌入汇编
5、预处理
1)#error
Q:预处理器标识#error的目的是什么?
A:保证程序是按照所设想的方式执行
6、变量a的8种定义用法
- 一个整型数:int a
- 一个指向整型数的指针: int *a
- 一个指向指针的指针,它指向的指针是指向一个整型数: int **a
- 一个有10个整型数的数组: int a[10];
- 一个有10个指针的数组,该指针是指向一个整型数的。: int *a[10];
- 一个指向有10个整型数数组的指针:int (*a)[10];
- 一个指向函数的指针,该函数有一个整型参数并返回一个整型数: int (*a)(int);
- 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数:int (*a[10])(int);
7、函数指针 VS 指针函数
1)指针函数
本质是一个函数,该函数的返回值是一个指针,声明格式如下:
类型标识符* 函数名(参数表)
指针函数的声明如下:
int *fun (int x,int y);
注意:
在调用指针函数时,需要用同一个类型的指针来接收其函数的返回值。
2)函数指针
函数指针,其本质是一个指针变量,该指针指向这个函数,其声明格式:
类型说明符 (*函数名)(参数)
函数指针的声明如下:
int (*fun) (int x,int y);
8、关键字const
const 意味着“只读”,const是定义常变量的关键字,使用const关键字的作用:
- 为阅读代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉用户这个参数的应用目的
- 通过给优化器一些附加的信息
- 是编译器保护那些不希望被改变的参数,防止被无意的代码修改
9、关键字volatile
Volatile修饰的变量意味着可能会被意想不到的改变。精确地说,优化器在用到这个变量时,必须每次小心地重新读取这个变量的值,而不是使用保存在寄存器里面的备份。Volatile 实例:
-
- 并行设备的硬件寄存器
- 一个中断服务子程序中会访问到的非自动变量
- 多线程应用中被几个任务共享的变量。
注意点:
- 一个参数既可以是const的还可以是volatile? 为什么?
可以的,它是volatile因为它可能被意想不到的改变,它是const因为程序不应该试图修改它
- 一个指针可以是volatile?为什么?
可以的,例如:当一个中断服务程序指向一个buffer的指针时
- 下面的函数有什么错误?该如何修改
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
======================
答:因为*ptr 可能被意想不到的修改,所以两次*ptr的值可能不一样,导致结果并非为想要的平方值。正确代码应该如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}