目录
一、命令行的定义
在linux环境下
#include <stdio.h>
int main()
{
int arr[SZ] = { 0 };
int i = 0;
for (i = 0; i < SZ; i++)
{
arr[i] = i;
}
for (i = 0; i < SZ; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
会报错未定义,此时gcc test.c -D SZ = 10,这样就会输出正常。有些代码,可以允许在编译过程中更改,这也就是命令行定义,整个过程是在预编译阶段进行更改。
编译指令:gcc -D ARRAY_SIZE=10 program.c,对应上面就是gcc -D SZ = 10 test.c,不过顺序可调换。
二、条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的,因为我们有条件编译指令
#include <stdio.h>
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int i = 0;
for (i = 0; i < 10; i++)
{
arr[i] = 0;
#ifdef DEBUG
printf("%d ", arr[i]);
#endif
}
return 0;
}
如果#define DEBUG,那么这个语句就可以打印,没有,那么预编译阶段就会删掉这个代码
常见的条件编译指令
条件编译指令决定的是这个代码能否被执行
1、#enif
像这样
#if 1/0 (真/假)
printf("%d ", arr[i]);
#endif
2、多个分支的条件编译
#if 常量表达式
#elif 也就是else if
#else
#endif
3、判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
就像上面的代码,如果定义DEBUG,就会打印那条语句。
4、嵌套指令
#if defined(OS_UNIX)
#ifdef OPINTON
unix_version_option1();
#endif
#ifdef OPINTON2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPINTON2
msdos_version_option2();
#endif
#endif
嵌套判断
三、文件包含
#include 指令可以使另一个文件被编译。可以把这个文件包含到#include来进行编译
Project2.c
#include <stdio.h>
#include "add.h"
int main()
{
int ret = Add(2, 3);
printf("ret = %d\n", ret);
return 0;
}
add.h
int Add(int x, int y);
add.c
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
这样就是文件包含。
头文件包含方式
头文件的包含就是把文件中的内容拷贝过来
如果是本地文件,也就是自己创建的文件,用" "包含
查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。如果找不到就提示编译错误。
linux环境的标准头文件的路径:/user/include
如果是库文件,那就用<>
查找头文件直接去标准路径下去查找,如果找不到就提示编译错误
虽然""查找的范围更广,也可以用于引stdio.h这些库文件,但是更费时间
嵌套文件包含
如果多次包含同一份文件,那么内容就会被拷贝多次,这样就会造成冗余了,代码重复多了。
解决办法就是如果是test.h被多次包含
#ifndef __TEST_H__
#define __TEST_H__
int Add(int x, int y);
#endif
这样就会包含一次
或者
#pragma once
int Add(int x, int y);
意思就是只调用一次
四、练习
编写宏,计算结构体中某变量相对于首地址的偏移,并给出说明
此处应用到offsetof这个宏
#include <stdio.h>
struct S
{
char c1;
int a;
char c2;
};
int main()
{
printf("%d\n", offsetof(struct S, c1));
printf("%d\n", offsetof(struct S, a));
printf("%d\n", offsetof(struct S, c2));
return 0;
}
offsetof是个宏,需要头文件
size_t offsetof(struct Name, member Name)
头文件就是<stddef.h>。最后结果是0,4,8
模拟实现这个宏
偏移量的产生是两个地址的差值,单位是字节。
所以
#define OFFSETOF(struct_name, member_name) (int*)&(((struct_name*)0)->member_name)
把0强制传唤成结构体类型,指向成员,并取出地址,在转换成int类型,输出数字。当起始位置为0时,哪个成员的地址就是它的偏移量
结束。