学习自狄泰软件学院唐佐林老师C语言课程,文章中图片取自老师的PPT,仅用于个人笔记。
实验1 :#pragma message 和 #pragma once 的使用
实验2 : #pragma pack 和 内存对齐
实验3:结构体内存对齐方式分析
实验4 : 内存对齐—微软面试题
实验1 :#pragma message 使用
#include
#if defined(ANDROID20)
#pragma message("Compile Android SDK 2.0...")
#define VERSION "Android 2.0"
#elif defined(ANDROID23)
#pragma message("Compile Android SDK 2.3...")
#define VERSION "Android 2.3"
#elif defined(ANDROID40)
#pragma message("Compile Android SDK 4.0...")
#define VERSION "Android 4.0"
#else
#error Compile Version is not provided!
#endif
int main()
{
printf("%s\n", VERSION);
return 0;
}
mhr@ubuntu:~/work/C$
mhr@ubuntu:~/work/C$ gcc 24-1.c //没有定义 宏,通过 #error 输出编译报错
24-1.c:13:6: error: #error Compile Version is not provided!
#error Compile Version is not provided!
^
24-1.c: In function ‘main’:
24-1.c:18:20: error: ‘VERSION’ undeclared (first use in this function)
printf("%s\n", VERSION);
^
24-1.c:18:20: note: each undeclared identifier is reported only once for each function it appears in
mhr@ubuntu:~/work/C$
mhr@ubuntu:~/work/C$
mhr@ubuntu:~/work/C$ gcc -DANDROID40 24-1.c //命令行定义宏 输出我们想输出的指定编译信息
24-1.c:10:13: note: #pragma message: Compile Android SDK 4.0...
#pragma message("Compile Android SDK 4.0...")
^
mhr@ubuntu:~/work/C$
mhr@ubuntu:~/work/C$ ./a.out
Android 4.0
mhr@ubuntu:~/work/C$
ifndef 这种方式是被C语言所支持的,他并不是只包含了一次头文件,而是包含了多次,只是在包含多次的时候通过一个宏来控制头文件是否被嵌入到源代码的方式,也就是说 通过宏的方式来保证 头文件的内容只被嵌入到源文件一次,但是起始也包含了多次,预处理器还是处理了多次,所以说从效率上来说,这个方法不是很高。而 #pragma once 直接告诉预处理器 当前文件只 include 一次,后面的不处理,所以效率很高。而我们在代码里经常看到 ifndef这种方式 很少看到 #pragma once 是因为,once 这个参数 并不是所有的编译器都支持的,不好移植。
使用:
xxx.h
#pragma once
int g_value = 1;
或者 预处理器将忽略他不认识的 pragma 参数
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#pragma once
int g_value = 1;
#endif
实验2 : #pragma pack 和 内存对齐
#include
struct Test1
{
char c1;
short s;
char c2;
int i;
};
struct Test2
{
char c1;
char c2;
short s;
int i;
};
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
return 0;
}
mhr@ubuntu:~/work/C$ gcc 24-3.c
24-3.c: In function ‘main’:
24-3.c:23:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
^
24-3.c:24:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
^
mhr@ubuntu:~/work/C$ ./a.out
sizeof(Test1) = 12
sizeof(Test2) = 8
mhr@ubuntu:~/work/C$
实验3:结构体内存对齐方式分析
#include
#pragma pack(4)
//条件步骤如下:
//1 结构体 第一个成员起始于0
//2 每个成员按其类型大小和pack参数中较小的一个进行对齐,作为对齐参数
//3 成员偏移地址必须能被对齐参数整除
//4 结构体总长度必须是所有对齐参数的整数倍
struct Test1
{ //对齐参数 偏移地址 大小
char c1; // 1 0 1
short s; // 2 2 2
char c2; // 1 4 1
int i; // 4 8 4
};
#pragma pack()
#pragma pack(4)
struct Test2
{ //对齐参数 偏移地址 大小
char c1; // 1 0 1
char c2; // 1 1 1
short s; // 2 2 2
int i; // 4 4 4
};
#pragma pack()
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
return 0;
}
mhr@ubuntu:~/work/C$ gcc 24-3.c
24-3.c: In function ‘main’:
24-3.c:25:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
^
24-3.c:26:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
^
mhr@ubuntu:~/work/C$
mhr@ubuntu:~/work/C$
mhr@ubuntu:~/work/C$ ./a.out
sizeof(Test1) = 12
sizeof(Test2) = 8
mhr@ubuntu:~/work/C$
实验4 : 内存对齐—微软面试题
#include
#pragma pack(8)
struct S1
{ //对齐参数 偏移地址 大小
short a; // 2 0 2
long b; // 4 4 4
};
//条件步骤如下:
//1 结构体 第一个成员起始于0
//2 每个成员按其类型大小和pack参数中较小的一个进行对齐,作为对齐参数
//3 成员偏移地址必须能被对齐参数整除
//4 结构体总长度必须是所有对齐参数的整数倍
//5 结构体成员中结构体变量的大小取 该结构体变量所对应结构体内部长度最大的数据成员作为其大小
struct S2
{ //对齐参数 偏移地址 大小
char c; // 1 0 1
struct S1 d; // 4 4 8
double e; // 8 16 8
};
#pragma pack()
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
理论上 应该打印
8
24
在其他编译器上编译 VC编译器 编译结果是我们计算的结果。
为什么会这样呢?是因为gcc 编译器暂时不支持 8字节 对齐。他会忽略 #pragma pack(8) 直接使用默认字节对齐数4来操作,所以最后输出是四字节对齐的结果。