C语言学习记录——유십 C语言预处理(4)

本文详细介绍了C语言中的预处理指令,包括命令行定义如何改变编译行为,如`gcc -DSZ=10 test.c`;条件编译指令如`#ifdef`、`#ifndef`等用于根据条件选择性编译代码;文件包含的使用,避免代码冗余,并讲解了头文件包含的策略。同时,文章提供了实践示例,帮助读者更好地理解这些概念。
摘要由CSDN通过智能技术生成

目录

一、命令行的定义

二、条件编译

常见的条件编译指令

1、#enif

2、多个分支的条件编译

3、判断是否被定义

4、嵌套指令

三、文件包含

头文件包含方式

嵌套文件包含 

四、练习


一、命令行的定义

在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时,哪个成员的地址就是它的偏移量

结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值