C语言结构体对齐、枚举、宏、联合体
结构体类型的定义和使用
这篇文章很详细,值得一看C语言结构体类型的定义和使用
结构体对齐问题
关于结构体对齐问题请阅读:结构体对齐规则及举例
系统指定类型的大小与系统有关,这里取
数据类型 | 字节 |
---|---|
char | 1 |
float | 4 |
double | 8 |
long double | 16 |
short int | 2 |
int | 4 |
long int | 8 |
long long int | 8 |
(1)按结构体最大成员对齐(32位机下double、long long按照4字节对齐) | |
案例一: |
struct A{
char a;
short b;
int a;
};
结果是8
案例二:
struct A{
int a;
double b;
};
结果是12并非16
(2)结构体嵌套
嵌套的结构体会在先内部完成对齐。
案例一:
struct A{
short a;
char b;
};
struct B{
struct A b;
char c;
int d;
};
结果是12,而非8
如果是:
案例二:
struct A{
short a;
char b;
char c;
int d;
};
则是8
(3)每个成员的起始位置必须是当前成员大小的整数倍
例如:
- short的起始位置必须是2的倍数。
- int、long long、double的起始位置必须是4的倍数。
- char则随便放,因为是1。
struct A{
char a;
short b;
int c;
};
b的偏移是2而非1
(4)在使用预编译指令指定对齐方式之后,一切听预编译指令
#pragma pack(nbytes)可以指定按nbytes字节对齐。
枚举常量与宏的区别
- 枚举常量属于常量,但宏不是常量;
- 枚举常量具有类型,但宏没有类型,枚举变量具有与普通变量相同的诸如作用域、值等性质,但宏没有,宏不是语言的一部分,它是一种预处理替换符。枚举类型主要用于限制性输入,例如,某个函数的某参数只接受某种类型中的有限个数值,除此之外的其它数值都不接受,这时候枚举能很好地解决这个问题。能用枚举尽量用枚举,否则在调试的时候你是看不到当时的值的。
- 枚举可以一次定义大量相关的常量,而#define 宏一次只能定义一个。
宏函数与普通函数对比
- 优点:
宏函数在预处理期间会进行宏替换,没有函数压栈开销,运行效率高。 - 缺点:
1、不安全(不会进行类型检测)
2、代码复用率不高
3、不停的进行替换,增长代码长度
4、不能调试
内联函数
概念
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率
特性
- inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的的函数不适宜使用内联
- inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联
- inline必须函数定义放在一起,才能成为内联函数,仅将inline放在声明前是不起作用的
- 定义在类内的成员函数默认定义为内联函数
注意事项
在C++中,强制建议使用const代替宏常量,使用内联函数代替宏函数,const和内联函数在进行编译时不仅进行替换,而且还会进行参数类型检测,提高了程序的安全性。内敛函数可以是普通函数,也可以是类的成员函数;函数式宏不能作为类的成员函数
宏与内联函数的区别
- 内联函数采用的是值传递,而宏定义采用的是对等替换.
- 宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销
- 编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
注意事项
- 在内联函数内不允许用循环语句和开关语句和递归。
- 内联函数的定义必须出现在内联函数第一次被调用之前。
宏与const的区别
- 用#define MAX 255定义的常量是没有类型的,所给出的是一个立即数,编译器只是把所定义的常量值与所定义的常量的名字联系起来,define所定义的宏变量在预处理的时候进行替换,在程序中使用到该常量的地方都要进行拷贝替换;
- 用const float MAX = 255; 定义的常量有类型名字,存放在内存的静态区域中,在程序运行过程中const变量只有一个拷贝,而#define 所定义的宏变量却有多个拷贝,所以宏定义在程序运行过程中所消耗的内存要比const变量的大得多;
- 用define定义的常量是不可以用指针变量去指向的,用const定义的常量是可以用指针去指向该常量的地址的;
- 用define可以定义一些简单的函数,const是不可以定义函数的.
具体来说,有以下几方面的区别
- 编译器处理方式
define – 在预处理阶段进行替换
const – 在编译时确定其值 - 类型检查
define – 无类型,不进行类型安全检查,可能会产生意想不到的错误
const – 有数据类型,编译时会进行类型检查 - 内存空间
define – 不分配内存,给出的是立即数,有多少次使用就进行多少次替换,在内存中会有多个拷贝,消耗内存大
const – 在静态存储区中分配空间,在程序运行过程中内存中只有一个拷贝 - 其他
1、在编译时, 编译器通常不为const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
2、宏替换只作替换,不做计算,不做表达式求解。
3、宏定义的作用范围仅限于当前文件。
4、默认状态下,const对象只在文件内有效,当多个文件中出现了同名的const变量时,等同于在不同文件中分别定义了独立的变量。 如果想在多个文件之间共享const对象,必须在变量定义之前添加extern关键字(在声明和定义时都要)。
联合体和结构体区别
- 两者都可以有多个成员,结构体是多个不同类型变量的组合,其占用的内存大小是所有变量大小的总和; 联合体多个不同类型的变量占用一份存储空间,其占用内存的大小是联合体中最大的那个变量的大小。
- 由于共用一份存储空间,所以对联合体的成员进行修改会顺带改变其他成员,结构体则不会。
C和C++结构体区别
- C的结构体内不允许有函数成员存在,C++允许有内部成员函数。所以C的结构体是没有构造函数、析构函数、和this指针的。
- C的结构体对内部成员变量的访问权限只能是public,而C++允许public,protected,private三种。
- C语言的结构体是不可以继承的,C++的结构体是可以从其他的结构体或者类继承过来的。
- 创建结构体对象的书写不同,C++直接用结构体名 变量名;而C要struct 结构体名 变量名;
- C结构体不可以有static成员。