自学内容网 自学内容网

【c/c++】编写头文件

(1)为什么要用头文件

不使用头文件,也可以编译多个源代码文件,比如有两个源代码,mymath.c test.c,像下面这样。

mymath.c

// mymath.c
// 函数的定义实现
int add(int a, int b)
{
    return a + b;
}

int max(int a, int b)
{
    return (a > b) ? a : b;
}

main.c

// main.c

#include <stdio.h>

// 函数的声明
int add(int a, int b);
int max(int a, int b);

int main()
{
    printf("%d\n", add(10, 20));
    printf("%d\n", max(10, 20));
    return 0;
}

编译和运行

[root@localhost test]# gcc mymath.c main.c -o main
[root@localhost test]# ./main
30
20
[root@localhost test]# 

对于以上例子,当外部的函数较多时,会在主代码文件main.c写较多的函数声明,使得主代码文件比较混乱,不方便代码的阅读和管理。因此需要头文件来专门统一管理函数等声明。

(2)头文件的使用

如果把函数原型放在一个头文件里,那么就不必每次使用函数时都声明其原型了。 把函数声明放入头文件是很好的习惯。
  • .c文件里放的是函数的定义
  • .h文件里面给方的是函数的声明

mymath.c

// mymath.c
// 函数的定义实现
int add(int a, int b)
{
    return a + b;
}

int max(int a, int b)
{
    return (a > b) ? a : b;
}

mymath.h

// mymath.h
int add(int a, int b);
int max(int a, int b);

main.c

#include <stdio.h>
#include "mymath.h"

int main()
{
    printf("%d\n", add(10, 20));
    printf("%d\n", max(10, 20));
    return 0;
}

编译和执行

gcc -o main main.c mymath.c
./main

(3)防止重复编译

对于刚才的mymath.h,如果在主文件中多次导入头文件,像下面这样,则会出现重复编译,带来相关问题

  1. 重复定义:同一个变量或函数在多个源文件中被重复定义,导致链接错误。
  2. 不必要的编译开销:每次包含头文件时,相关的代码会被重复编译多次。
  3. 依赖关系错误:若头文件依赖其他头文件,而这些依赖没有通过#include指令显式声明,可能会引发编译错误。
#include <stdio.h>
#include "mymath.h"
#include "mymath.h"
#include "mymath.h"

int main()
{
    printf("%d\n", add(10, 20));
    printf("%d\n", max(10, 20));
    return 0;
}

解决办法是在头文件中添加ifdef, ifndef和endif语句。#ifndef是个预编译指令,代表只要定义个常量,那么就预编译下面的代码。

#ifdef 宏
代码
#endif

头文件这样操作

// mymath.h
#ifndef __MYMATH_H__
#define __MYMATH_H__

int add(int a, int b);
int max(int a, int b);

#endif

也可以使用#pragma once

// mymath.h
#pragma once

int add(int a, int b);
int max(int a, int b);

(4)ifdef, ifndef和endif也可用在代码中

ifdef, ifndef和endif用在代码中提高兼容性或者方便调试

#include <stdio.h>
#include "mymath.h"

//#define TEST //定义一个宏,但没有任何值

int main()
{
    #ifdef TEST
    //如果定义了TEST这个宏
    //那么在预编译时会预编译 #ifdef TEST 和 #endif 之间的代码
    printf("hello world 1\n");
    #endif

    printf("%d\n", add(10, 20));
    printf("%d\n", max(10, 20));

    #ifndef TEST
    //如果没有定义TEST这个宏
    //那么在预编译时会预编译 #ifdef TEST 和 #endif 之间的代码
    printf("hello world 2\n");
    #endif
    
    return 0;
}

(5)在头文件中兼容C和C++编译器

示例头文件

//头文件函数声明
//防止头文件重复包含
#pragma once

//兼容C++编译器
//如果是C++编译器,则按c标准编译
#ifdef __cplusplus
extern "C"
{
#endif


int add(int a, int b);
int max(int a, int b);


#ifdef __cplusplus
}
#endif

#ifdef __cplusplus //如果是在c++编译器中,则会生成 __cplusplus 这个宏常量

extern "C" {/*....*/}后,会指示编译器这部分代码按C语言的进行编译,而不是C++的


原文地址:https://blog.csdn.net/hutaotaotao/article/details/137966421

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!