简图记录学习。
推荐一本C语言学习好书《C语言深度剖析》陈正冲,以下部分为本书中关于关键字的总结~:
1、register
告诉编译器尽可能在内部寄存器存储以提高访问效率;
约束:必须是寄存器能接受的单值类型,size<=int; 修饰的变量不能用&取地址,因为不在内存中
2、static
修饰限定作用域:修饰全局变量和修饰函数,表示只能在本文件引用、不可extern使用
标识存储在静态区:修饰局部变量, 表示函数结束后不返回;
3、sizeof
注意 是关键字而非函数、在编译时就计算完成,部分变量大小和编译环境相关。
数据类型 | 16位编译器 | 32位编译器 | 64位编译器 | |
char | 1 | 1 | 1 | |
指针变量 | 2 | 4 | 8 | |
short int | 2 | 2 | 2 | |
int | 2 | 4 | 4 | 各类系统数据定义,至少16bit |
float | 4 | 4 | 4 | |
double | 8 | 8 | 8 | |
long | 4 | 4 | 8 | 各类系统数据定义,至少32bit |
long long | 8 | 8 | 8 | 各类系统数据定义,至少64bit |
举例(32位编译环境):
int i;-->sizeof(int)、sizeof(i)、sizeof i都为4,sizeof int非法;int a[3];--->sizeof(a)为12;
4、signed和unsigned
计算机中数值使用补码存储,优势在于可将符号位统一处理,减法可按加负数计算;
补码表示方法:正数不变、负数最高位为 符号位1 其余位为绝对值按位取反后+1;
举例:如char型-1为0xff、-2为0xfe、-128为0x80--->-128再-1为0x80+0xff=0x7f(最高位被丢弃)
5、各类数据类型比0方法
if (bTestVal) { } // bool比较
if ((fTestVal >= -EPSINON) && (fTestVal <= EPSINON)) { } //float比较, EPSINON为精度如0.001
if (p == NULL) { } // 指针比较
6、switch case
case后面只能是 整型 或 字符型常量 或者 常量表达式
7、void
用法1:修饰函数入参或者返回值表示无参数;
用法2:作为void*指针可接受任意类型指针(void *指针 部分编译器 认为 计算非法如 p++);
void a定义非法
8、const
修饰 只读变量而非常量;
const int *p 对象只读;int const *p 对象只读;int * const p 指针只读;const int * const p 都只读
(技巧 先隐藏类型如int,然后const如果离*P近表示对象修饰、离p近表示对指针修饰)
注意 extern const int i = 10;不合法
9、volatile
修饰易变变量:该变量可能被未知因数如硬件、某个线程修改,访问该变量时不可优化,必须从内存获取;
注意:const volatile int i;只读可变变量,如修饰只读寄存器;
10、extern
修饰变量或者函数表示其定义在外部文件;
注意:extern int a=10;因为有赋值动作实际为定义和int a=10一样;
int a[100]可以使用extern int a[]引用而不能使用extern int *a;
补充一个在C++编译相关extern "C"用法:
(C++编译时为了解决函数多态问题实际在生成符号表时使用函数和参数生成新符号名,而C语言不会,为了保证C++编译器不做此转变可使用extern "C"{}保护代码,防止链接时找不到指定符号,__cplusplus是C++编译器带有的宏定义)
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
/*****C代码*****/
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
11、typedef
类型重命名关键字常用来:
1、隐藏明确数据类型 如内核中size_t,在不同的内核版本实际长度不一样可能为char或int等,不能强转使用影响代码一致性;2、定义更明确的数据长度类型(C语言除了char其他类型都没有标准规定一定是多长),在32位系统中typedef u32 unsigned int; 3、针对struct或者enum进行重命名,简化书写类型前缀同时也隐藏了数据类型;
#define PCHAR char*--->PCHAR i,j; 实际j只是char型
typedef char * pchar;--->pchar i,j; i和j都是char *类型
12、struct
struct大小规则(默认情况,未指定对齐编译命令下):
1、每个成员偏移量为其成员size整数倍,若不是在其前插入字节填充;
2、所有成员计算完成后,总大小必须是最大成员整数倍,若不是在尾部添加字节填充;
// 举例:
struct X {
char a;
/*b前填充3字节*/
float b;
int c;
/*d前填充4字节*/
double d;
int e;
/*尾部补充4字节*/
}
struct Y {
double a;
char b[30];
/*c前填充2字节*/
int c;
int d;
}
13、union
联合体定义,其大小为最大成员size;
// 大小端测试:
int checkIsLittleSystem(void) {
union check {
int i;
char j;
} c;
c.i=1;
return (c.j==1); /*小端返回1*/
}
14、enum
枚举定义,内部成员值若没指定则为上一个成员+1;
大小:默认编译按int存,若带fshort-enums为满足范围的最小size;(因此一般对外接口不建议使用enum入参)
符号(默认为无符号,除非定义时指定成员为负数则为有符号)
typedef enum {
MY_ENUM1_TYPE_A,
MY_ENUM1_TYPE_MAX
} my_enum1;
typedef enum {
MY_ENUM2_TYPE_A = -1,
MY_ENUM2_TYPE_MAX
} my_enum2;
int main() {
my_enum1 a = -1;
my_enum2 b = -1;
printf(" a > 0 = %d b > 0 = %d\n", a > 0, b > 0); // 输出 a > 0 = 1 b > 0 = 0
return 0;
}