精华内容
下载资源
问答
  • C语言引用头文件
    千次阅读
    2021-12-29 15:57:43

    C语言中引用头文件有两种方式:

    “”

    include<fileName.h> 引用系统头文件一般用<>。

    <>

    include"fileName.h" 引用自己定义的头文件一般用" "。

    更多相关内容
  • C语言头文件

    2018-05-06 13:18:39
    C语言头文件库大全,工具下载安装后扣出的所有头文件。
  • C语言头文件中定义const变量详解 在头文件中定义const不会有多变量的警告或错误,如果该头文件被大量包含会造成rom空间的浪费。 通过查看*.i文件的展开呢,可以发现每个.i文件都会有相应的变量展开。 查看*.map...
  • C语言头文件的编写规则,掌握后可以减少程序的BUG
  • c语言头文件下载 C语言头文件大全导读:就爱阅读网友为您分享以下“C语言头文件大全”资讯,希望对您有所帮助,感谢您对92的支持!标准C语言头文件ISOC标准定义的头文件(24项)验证程序断言支持复数算术运算出错码浮点...

    c语言头文件下载 C语言头文件大全

    导读:就爱阅读网友为您分享以下“C语言头文件大全”资讯,希望对您有所帮助,感谢您对92的支持!

    标准C语言头文件

    ISOC标准定义的头文件(24项)验证程序断言支持复数算术运算出错码

    浮点环境

    整型格式转换替代关系操作符宏局部类别数学常量信号可变参数表标准定义整型实用程序库函数字符串操作时间和日期

    宽字符支持

    POSIX标准定义的必须的头文件(26项)目录项

    文件控制路径名模式匹配类型组文件口令文件正则表达式终端I/O符号常量

    字扩展类型

    Internet定义

    Internet地址族传输控制协议select函数套接字接口进程时间基本系统数据类型系统名

    进程控制

    POSIX标准定义的XSI扩展头文件(26项)cpio归档值动态链接

    文件树漫游

    代码集转换实用程序模式匹配函数定义货币类型消息类别轮询函数

    字符串操作系统出错日志记录用户限制用户帐户数据库消息队列资源操作共享存储文件系统信息附加的时间

    矢量I/O操作

    POSIX标准定义的可选头文件(8项)异步I/O消息队列执行调度

    信号量

    XSISTREAMS接口时间跟踪

    字符类型浮点常量实现常量非局部goto布尔类型和值标准I/O库通用类型数学宏宽字符分类和映射支持

    文件名匹配类型网络数据库操作tar归档值文件时间套接字本地接口内存管理声明文件状态UNIX域套接字定义

    消息显示结构语言信息常量数据库操作搜索表用户上下文IPC信号量时间类型

    线程

    展开全文
  • C头文件,分享给有需要朋友。有需要可以下来试试。C/C++用户与单片机开发的朋友。比较适用。
  • C语言常用头文件

    千次阅读 2021-04-01 17:44:02
    } 运行结果 ctype.h 借鉴自C标准库 定义了一批C语言字符分类函数(C character classification functions),用于测试字符是否属于特定的字符类别,如字母字符、控制字符等等。既支持单字节字符,也支持宽字符。 ...

    stdio.hstandard input & output

    标准输入输出

    stdlib.hstandard library

    标准库头文件。

    里面定义了五种类型、一些宏和通用工具函数。类型例如size_t、wchar_t、div_t、ldiv_t和lldiv_t; 宏例如EXIT_FAILURE、EXIT_SUCCESS、RAND_MAX和MB_CUR_MAX等等; 常用的函数如malloc()、calloc()、realloc()、free()、system()、atoi()、atol()、rand()、srand()、exit()等等。

    string.h

    借鉴自C 标准库 - <string.h>

    头文件定义了一个变量类型、一个宏和各种操作字符数组的函数。

    1. 库变量类型
      size_t
      这是无符号整数类型,它是 sizeof 关键字的结果。

    2. 库宏
      NULL
      这个宏是一个空指针常量的值。

    3. 库函数

    • strcat()函数
      *原型:char *strcat(char *dest, const char src)
      作用:把src所指向的字符串追加到dest 所指向的字符串的结尾。
    • strcmp()函数
      *原型:int strcmp(const char *str1, const char str2)
      作用:把 str1 所指向的字符串和 str2 所指向的字符串进行比较。
    • strcpy()函数
      *原型:char *strcpy(char *dest, const char src)
      作用:把 src 所指向的字符串复制到 dest。
    • strlen()函数
      *原型:size_t strlen(const char str)
      作用:计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。
    • memchr()函数
      *原型:void *memchr(const void str, int c, size_t n)
      作用:在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。
    • memcmp()函数
      *原型:int memcmp(const void *str1, const void str2, size_t n)
      作用:把 str1 和 str2 的前 n 个字节进行比较。
    • memcpy()函数
      *原型:void *memcpy(void *dest, const void src, size_t n)
      作用:从 src 复制 n 个字符到 dest。
    • memmove()函数
      *原型:void *memmove(void *dest, const void src, size_t n)
      作用:另一个用于从 src 复制 n 个字符到 dest 的函数。
    • memset()函数
      *原型:void *memset(void str, int c, size_t n)
      作用:复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
    • strncat()函数
      *原型:char *strncat(char *dest, const char src, size_t n)
      作用:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。
    • strchr()函数
      *原型:char *strchr(const char str, int c)
      作用:在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
    • strncmp()函数
      *原型:int strncmp(const char *str1, const char str2, size_t n)
      作用:把 str1 和 str2 进行比较,最多比较前 n 个字节。
    • strcoll()函数
      *原型:int strcoll(const char *str1, const char str2)
      作用:把 str1 和 str2 进行比较,结果取决于 LC_COLLATE 的位置设置。
    • strncpy()函数
      *原型:char *strncpy(char *dest, const char src, size_t n)
      作用:把 src 所指向的字符串复制到 dest,最多复制 n 个字符。
    • strcspn()函数
      *原型:size_t strcspn(const char str1, const char str2)
      作用:检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。
    • strerror()函数
      *原型:char strerror(int errnum)
      作用:从内部数组中搜索错误号errnum,并返回一个指向错误消息字符串的指针。
    • strpbrk()函数
      *原型:char *strpbrk(const char *str1, const char str2)
      作用:检索字符串 str1 中第一个匹配字符串 str2 中字符的字符,不包含空结束字符。也就是说,依次检验字符串 str1 中的字符,当被检验字符在字符串 str2 中也包含时,则停止检验,并返回该字符位置。
    • strrchr()函数
      *原型:char *strrchr(const char str, int c)
      作用:在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。
    • strspn()函数
      *原型:size_t strspn(const char *str1, const char str2)
      作用:检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标。
    • strstr()函数
      *原型: char *strstr(const char *haystack, const char needle)
      作用:在字符串 haystack 中查找第一次出现字符串 needle(不包含空结束字符)的位置。
    • strtok()函数
      *原型: char *strtok(char *str, const char delim)
      作用:分解字符串 str 为一组字符串,delim 为分隔符。
    • strxfrm()函数
      *原型:size_t strxfrm(char *dest, const char src, size_t n)
      作用:根据程序当前的区域选项中的 LC_COLLATE 来转换字符串 src 的前 n 个字符,并把它们放置在字符串 dest 中。

    math.h

    头文件中声明了常用的一些数学运算

    1. 三角函数
      double sin(double);正弦
      double cos(double);余弦
      double tan(double);正切

    2. 反三角函数
      double asin (double); 结果介于[-PI/2,PI/2]
      double acos (double); 结果介于[0,PI]
      double atan (double); 反正切(主值),结果介于[-PI/2,PI/2]
      double atan2 (double,double); 反正切(整圆值),结果介于[-PI,PI]

    3. 双曲三角函数
      double sinh (double);
      double cosh (double);
      double tanh (double);

    4. 指数与对数
      double frexp(double value,int *exp);这是一个将value值拆分成小数部分f和(以2为底的)指数部分exp,并返回小数部分f,即f·2^exp。其中f取值在0.5~1.0范围或者0。
      double ldexp(double x,int exp);这个函数刚好跟上面那个frexp函数功能相反,它的返回值是x*2^exp
      double modf(double value,double *iptr);拆分value值,返回它的小数部分,iptr指向整数部分。
      double log (double); 以e为底的对数
      double log10 (double);以10为底的对数
      double pow(double x,double y);计算x的y次幂
      float powf(float x,float y); 功能与pow一致,只是输入与输出皆为单精度浮点数
      double exp (double);求取自然数e的幂
      double sqrt (double);开平方根

    5. 取整
      double ceil (double); 取上整,返回不比x小的最小整数
      double floor (double); 取下整,返回不比x大的最大整数,即 高斯函数[x]

    6. 绝对值
      int abs(int i); 求整型的绝对值
      double fabs (double);求实型的绝对值
      double cabs(struct complex znum);求复数的绝对值

    7. 标准化浮点数
      double frexp (double f,int *p); 标准化浮点数,f = x * 2^p,已知f求x,p (x介于[0.5,1])
      double ldexp (double x,int p); 与frexp相反,已知x,p求f

    8. 取整与取余
      double modf (double,double*); 将参数的整数部分通过指针回传,返回小数部分
      double fmod (double,double); 返回两参数相除的余数

    9. 其他
      double hypot(double x,double y);已知直角三角形两个直角边长度,求斜边长度
      double ldexp(double x,int exponent);计算x*(2的exponent次幂)
      double poly(double x,int degree,double coeffs []);计算多项式
      int matherr(struct exception *e);数学错误计算处理程序

    source: 《C & C++ Code Capsules》

    assert.h

    头文件提供了一个名为 assert 的宏

    void assert(int expression)
    这实际上是一个宏,不是一个函数,可用于在 C 程序中添加诊断。它可用于验证程序做出的假设,并在假设为假时输出诊断消息。

    limits.h

    转载自C 标准库 - <limits.h>

    头文件决定了各种变量类型的各种属性。定义在该头文件中的宏限制了各种变量类型(比如 char、int 和 long)的值。
    这些限制指定了变量不能存储任何超出这些限制的值,例如一个无符号可以存储的最大值是 255。

    库宏

    描述
    CHAR_BIT8定义一个字节的比特数。
    SCHAR_MIN-128定义一个有符号字符的最小值。
    SCHAR_MAX127定义一个有符号字符的最大值。
    UCHAR_MAX255定义一个无符号字符的最大值。
    CHAR_MIN0定义类型 char 的最小值,如果 char 表示负值,则它的值等于 SCHAR_MIN,否则等于 0。
    CHAR_MAX127定义类型 char 的最大值,如果 char 表示负值,则它的值等于 SCHAR_MAX,否则等于 UCHAR_MAX。
    MB_LEN_MAX1定义多字节字符中的最大字节数。
    SHRT_MIN-32768定义一个短整型的最小值。
    SHRT_MAX+32767定义一个短整型的最大值。
    USHRT_MAX65535定义一个无符号短整型的最大值。
    INT_MIN-2147483648定义一个整型的最小值。
    INT_MAX2147483647定义一个整型的最大值。
    UINT_MAX4294967296定义一个无符号整型的最大值。
    LONG_MIN-9223372036854775808定义一个长整型的最小值。
    LONG_MAX9223372036854775807定义一个长整型的最大值。
    ULONG_MAX1.8446744e+19定义一个无符号长整型的最大值。

    实例

    #include <stdio.h>
    #include <limits.h>
    
    int main()
    {
    
       printf("The number of bits in a byte %d\n", CHAR_BIT);
    
       printf("The minimum value of SIGNED CHAR = %d\n", SCHAR_MIN);
       printf("The maximum value of SIGNED CHAR = %d\n", SCHAR_MAX);
       printf("The maximum value of UNSIGNED CHAR = %d\n", UCHAR_MAX);
    
       printf("The minimum value of SHORT INT = %d\n", SHRT_MIN);
       printf("The maximum value of SHORT INT = %d\n", SHRT_MAX);
    
       printf("The minimum value of INT = %d\n", INT_MIN);
       printf("The maximum value of INT = %d\n", INT_MAX);
    
       printf("The minimum value of CHAR = %d\n", CHAR_MIN);
       printf("The maximum value of CHAR = %d\n", CHAR_MAX);
    
       printf("The minimum value of LONG = %ld\n", LONG_MIN);
       printf("The maximum value of LONG = %ld\n", LONG_MAX);
     
       return(0);
    }
    

    运行结果

    在这里插入图片描述

    ctype.h

    借鉴自C标准库<ctype.h>

    定义了一批C语言字符分类函数(C character classification functions),用于测试字符是否属于特定的字符类别,如字母字符、控制字符等等。既支持单字节字符,也支持宽字符。

    库函数

    • int isalnum(int c)
      该函数检查所传的字符是否是字母和数字。
    • int isalpha(int c)
      该函数检查所传的字符是否是字母。
    • int iscntrl(int c)
      该函数检查所传的字符是否是控制字符。
    • int isdigit(int c)
      该函数检查所传的字符是否是十进制数字。
    • int isgraph(int c)
      该函数检查所传的字符是否有图形表示法。
    • int islower(int c)
      该函数检查所传的字符是否是小写字母。
    • int isprint(int c)
      该函数检查所传的字符是否是可打印的。
    • int ispunct(int c)
      该函数检查所传的字符是否是标点符号字符。
    • int isspace(int c)
      该函数检查所传的字符是否是空白字符。
    • int isupper(int c)
      该函数检查所传的字符是否是大写字母。
    • int isxdigit(int c)
      该函数检查所传的字符是否是十六进制数字。
    • int tolower(int c)
      该函数把大写字母转换为小写字母。
    • int toupper(int c)
      该函数把小写字母转换为大写字母。

    <time.h>

    转载自C 标准库 - <time.h>

    头文件定义了四个变量类型、两个宏和各种操作日期和时间的函数。

    库变量

    • size_t
      是无符号整数类型,它是 sizeof 关键字的结果。
    • clock_t
      这是一个适合存储处理器时间的类型。
    • time_t is
      这是一个适合存储日历时间类型。
    • struct tm
      这是一个用来保存时间和日期的结构。
      tm 结构的定义如下:
    struct tm {
       int tm_sec;         /* 秒,范围从 0 到 59        */
       int tm_min;         /* 分,范围从 0 到 59        */
       int tm_hour;        /* 小时,范围从 0 到 23        */
       int tm_mday;        /* 一月中的第几天,范围从 1 到 31    */
       int tm_mon;         /* 月,范围从 0 到 11        */
       int tm_year;        /* 自 1900 年起的年数        */
       int tm_wday;        /* 一周中的第几天,范围从 0 到 6    */
       int tm_yday;        /* 一年中的第几天,范围从 0 到 365    */
       int tm_isdst;       /* 夏令时                */
    };
    

    库宏

    • NULL
      这个宏是一个空指针常量的值。
    • CLOCKS_PER_SEC
      这个宏表示每秒的处理器时钟个数。

    库函数

    • char *asctime(const struct tm *timeptr)
      返回一个指向字符串的指针,它代表了结构 timeptr 的日期和时间。
    • clock_t clock(void)
      返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。
    • char *ctime(const time_t *timer)
      返回一个表示当地时间的字符串,当地时间是基于参数 timer。
    • double difftime(time_t time1, time_t time2)
      返回 time1 和 time2 之间相差的秒数 (time1-time2)。
    • struct tm *gmtime(const time_t *timer)
      timer 的值被分解为 tm 结构,并用协调世界时(UTC)也被称为格林尼治标准时间(GMT)表示。
    • struct tm *localtime(const time_t *timer)
      timer 的值被分解为 tm 结构,并用本地时区表示。
    • time_t mktime(struct tm *timeptr)
      把 timeptr 所指向的结构转换为一个依据本地时区的 time_t 值。
    • size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)
      根据 format 中定义的格式化规则,格式化结构 timeptr 表示的时间,并把它存储在 str 中。
    • time_t time(time_t *timer)
      计算当前日历时间,并把它编码成 time_t 格式。
    展开全文
  • 大家好,先做个自我介绍,我是天蓬,欢迎阅读本篇博文。... 好了,我们步入正题,今天来说说C语言中的头文件如何使用,到底什么时候需要我们自己写一个头文件,如何来写,以及动态库和静态库的扩展,带着疑...

            大家好,先做个自我介绍,我是天蓬,欢迎阅读本篇博文。

    由于本人理解能力不是很好,阅读他人文章时,常常看得晕头晕脑,这让我很是头疼,我想,世界上一定还有和我一样的人(哈哈,不是说你么笨哦)。所以,我将会立足于读者的角度,以读者思维来进行讲解,如果你阅读完后觉得还不错的话,可以点个赞鼓励一下,当然如果对你没有任何帮助,你也可以在评论区吐槽我,让我意识到有哪些地方需要改进。

            好了,我们步入正题,今天来说说C语言中的头文件的作用,到底什么时候需要我们自己写一个头文件,如何来写,以及动态库和静态库的扩展,带着这些疑问我们往下看。


    目录

    1.什么时候需要头文件

    2.如何自定义头文件,以及定义头文件时的注意事项

    3.扩展:动态库与静态库

    4.总结 


     1.什么时候需要头文件

            首先,来看一个最基本的程序。

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
        printf("hello world");
    	return 0;
    }

           这里要是没了头文件,一定会编译不过。理由很简单,我们使用了printf()函数,而这个函数就是在#include <stdio.h>这个头文件中定义的。只不过,这个头文件和这个函数并不需要我们去编写,这是由于在C语言标准中就已经帮我们实现好了的,当然C语言标准中并不只是提供了这一个头文件。当我们需要使用某个函数我们去查询对应的头文件,然后引入即可(linux中的man手册是个好动西)。

            所以,通过这里我们知道,什么时候需要头文件?当然是我需要调用某个函数时,而这个函数是已经定义好的,我们直接引用对应的头文件即可(相当于将头文件中的内容引入到当前文件,如果你还不熟悉头文件或者没有尝试过自己编写,请继续往下看);


    2.如何自定义头文件,以及定义头文件时的注意事项

            继续看下面的代码。

    #include <stdio.h>
    
    int add(int a, int b);
    
    int main(int argc, char const *argv[])
    {
    	printf("hello world\n");
    
    	int a=500;
    	int b=20;
    	printf("%d\n", add(a,b));
    
    	return 0;
    }
    
    int add(int a, int b){
    	return a+b;
    }

            这里我们实现两个整数相加,定义了一个名为add的加法函数,并在main函数前声明。对于才开始学习C语言的人来说,经常会以这种方式来编写函数,但是,你有没有想过,写一个这样的函数还好,万一你要自定义一百个,一千个或者更多的函数,难道我们还是得在同一个.c中写吗,显然这样是十分不规范的。
            当我们需要自定义函数时,我们通常会将函数单独编写,并书写对应的头文件即可。这样既符合规范,提高代码的重用性,也便于我们去维护代码,毕竟,在一些复杂的项目中,一份易于维护的代码非常关键。

            那么,我们该如何将这个函数单独编写,并书写对应的头文件?

            (1)编写一个c文件,这里我叫做myadd.c,然后实现加法函数。

    int add(int a, int b){
    	return a+b;
    }

            很简单,我们将add()函数的实现写入到myadd.c中。

          (2)编写对应的头文件,myadd.h,最好是和c文件名对应,如果你偏不这样干,那么也是完全可以的。

    #ifndef _MYADD_H_
    #define _MYADD_H_
    
    int add(int a, int b);
    
    #endif

            头文件中写入函数的声明即可。这里的ifndef,define为条件编译,是为了防止函数等被重复定义。

            (3)主函数中,引入头文件即可。

    #include <stdio.h>
    #include "myadd.h"
    
    int main(int argc, char const *argv[])
    {
    	printf("hello world\n");
    
    	int a=500;
    	int b=20;
    	printf("%d\n", add(a,b));
    
    	return 0;
    }
    

            整个目录结构如下:


           然后,我们使用gcc main.c myadd.c -o main 编译运行即可。

           通过以上三步,就完成了自定义头文件和源文件的编写,是不是非常简单。细心一点的读者可能会发现,myadd.c中就只有函数的实现,是不是少了点什么,的确,按照惯例来说,它缺少了对自身头文件的引用。(其实,从这里我们可以看出,头文件和源文件除了函数名称对应以外,并没有其它的任何关联,即头文件的定义和源文件是相互独立的,是两个文件,真正的关联是在函数运行过程中进行的,也就是说,我们程序运行时,当我们调用到这个函数后,才会通过你调用的函数名称去寻找对应的函数并执行(即函数的入栈),但是在编译阶段,编译器并不关心这个函数的实现,它只关心有没有这个函数,比如这里调用的add加法函数,在编译阶段,编译器找到了在myadd.c中已经定义了这个函数,编译器就认为是没有问题的,至于你有几个参数,参数是什么类型,它才不会管)。由于C语言中没有涉及多态的概念,这就从本质上决定了和C++的编译方式是有区别的,那是什么区别?

            C语言中,绝不允许同名函数的存在,即使参数不同也不行。但是C++中就可以。比如,在C语言中,写一个整数的加法和浮点数的加法,那么就意味着你必须定义两个函数名称不同的方法。而在C++中大可不必,这是由于C语言编译时,并不会去对参数做具体的判断。那么问题来了,如果不对参数做判断,那我们有一天突然在写代码时,打瞌睡写成这个样子了,会怎样?

    int add(int a, int b,int c){
    	return a+b;
    }

            这里我们参数多加了一个,但如果你编译的话,会惊奇的发现居然通过了。但是,我们如果运行这个程序,肯定是会报错的,因为我们调用时只给函数传了两个参数,实际上它却是三个参数。所以,这样的话,如果我们稍不留神,就会导致定义和声明不一致,编译却通过了,这种问题排查起来就会比较麻烦又耗费时间,领导就会来找你麻烦了,那么有没有解决的方式?肯定是有的。

            我们在自定义头文件时,引用自己的头文件即可,这样就相当于将函数的定义和声明,放到同一个文本中【别把头文件和c文件想得多高大上,其实就是个普通的问本文件而已,相当于王麻子改了个名叫老王】,如果定义和声明不一致,在编译阶段就会报错 ,将错误扼杀在摇篮当中。如下:

    #include "myadd.h"
    int add(int a, int b){
    	return a+b;
    }

             这样,就必须保证函数的定义和头文件中的一致。并且,引用自己的头文件并不只是这个作用,我们如果需要使用头文件中定义的其它内容时,也要引用,这里的其它内容在书写头文件的注意事项中有介绍。所以,我们在源文件中正常情况下都要引用自身的头文件。有很多小伙伴都是只知道要这样写,并不知道这样写的意义是什么,或者理解得不够全面。

           这里,我简单的总结一下自定义头文件有哪些注意事项:

            a.源文件名和头文件名称保持一致(如myadd.h和myadd.c)

            b.源文件中引入自身头文件,这样避免了函数的声明和定义不一致带来的麻烦

            c.头文件中只能存在函数的原型(声明),结构体,联合体,宏,枚举,变量。不要将函数定义写在头文件中,当然这样写也不会报错,因为本质上它们都是文本,但是不报错不代表就是对的。

            d.include<>,include " "的区别,上面的例子中,我们就是使用了#include "myadd.h",这个和<>的唯一区别就在于搜索路径不同。<>代表从定义的标准库中去查找,而" "代表从当前路径查找,显然,我么定义的myadd.c在当前路径,并不在标准库中。


    3.动态库与静态库

            通过前面的讲解,我们已经知道如何为源文件添加对应的头文件了。我们之所以要这样做,无非是有两个目的,一是方便自己,使得自己的代码更具有工程思维,也便于维护。二是方便他人,我们可以将写好的源文件和和头文件,提供给别人使用,这样,也可以便于合作开发。但是,现实中,我们并不会直接将源文件提供给别人,而是以库的形式来提供给第三方。

            为什么要提供库,而不是直接将源文件和头文件给别人呐?那是因为提供库比直接提供源文件有以下好处:

            a.可以保护知识产权;假如我们花费了三个月写的代码,需要提供给其他公司,但是我也并不想其它公司的人可以看到我是如何写的,这个时候就可以将代码封装成库再提供。

            b.易于迭代;假如你们公司最近开发了一个软件,并且已经批量的给客户使用了,但是,客户在使用的过程中,突然发现有bug,这个时候怎么办?当然是修改代码,然后修复后重新提供一个新的版本给客户使用就行了。但是,这就意味着,你只是修改了一小点,而用户需要更新全部,下载新的版本,这样显然不可取。可取的是,我们将函数功能封装成库,提供给用户。我们修复bug时,只需要重新生成一个新的库,而不必重新提供整个版本,这就是我们常说的打补丁了。

            c.更加高效和规范;你想,我们在开发过程中,常常会 写很多功能相同的函数,如果每一次都要重复去写,那就很费时费力了。通常的做法是,我们把这些功能相同的函数,用库封装起来,下一次编写时,就不用再去书写了,而是直接导入头文件即可,省时省力。

            上面说了这么多,也还没说库到底是个啥,我们又如何去将我们的.c生成为库呐?不急我们接着往下看。

            先来个三联问:什么是库?库的种类与区别?如何将源文件打包成库?如何使用库?下面我们围绕这几个问题来展开讲解。

          (1)什么是库?

            库又叫函数库,见名知意,它一般是我们在程序中需要反复使用的一些函数,比如,我们常写的#include <stdio.h>中就有我们常常需要使用的scanf()和printf()函数。

           (2)库的种类与区别?

            我们一般将库分为动态库和静态库;其中静态库的命名以lib为开头.a为后缀,比如libadd.a;动态库的命名以lib为开头.so为后缀,比如libadd.so。这是命名上的区别。

            其次,静态库和动态库的编译方式和载入时机都是不一样的,这里先说载入时机;静态库是在我们编译源文件时,就将静态库和源文件一起编译,生成可执行的二进制文件。 而动态库是在我们程序运行时才会去加载,如果你对C语言编译的四个阶段还不太了解的话,可以先补一下这方面的知识。刚刚说道,静态库时编译时就加载的,动态库运行时加载,那么这就意味着,我们开发的同一个程序,如果采取两种不同的方式,那么编译得到的可执行程序的文件大小一定是静态库大于动态库的,因为动态库编译时并不会加载库文件,只有 运行时才会加载。还值得一说的是,既然静态库编译时已经加载了,那是不是编译后就不需要它,程序就可以独立运行了呐?的确如此。相反,动态库是运行时才加载,所以如果程序运行时找不到这个动态库,那么一定会出现异常。在项目中要根据实际情况来决定具体要使用哪一种库,没有绝对的好坏之分。看了这些,如果你觉得有点抽象,那么你接着看看他们是如何制作与使用后,你就会恍然大悟了。

           (3)如何将源文件打包成库?

            还是沿用之前的例子,以加法为例来演示动态库和静态库的制作过程,我们这里简单介绍一下制作过程。这里还是再看看整个代码结构。

    一个主函数main.c,myadd.c里面是一个加法函数,myadd.h是对应的头文件,以此为例。

            静态库:将myadd.c打包成静态库

            a.gcc myadd.c -o myadd.o -c【myadd.o为重定向文件,如果你不知道这个的话,建议先熟悉一下C语言编译的4个过程】执行后会在当前文件生成一个myadd.o的新文件。如果我们有多个.c怎么办,简单,分别执行这条命令,myadd.o换成对应的名字即可。

            b.ar cr libadd.a myadd.o 【ar 为打包工具,cr为参数,如果需要请自行查询即可,再次说明man手册是非常强大的,如果你还不会,执行一下 man ar会有关于ar命令的详解;这里的libadd.a是我们根据静态库的命名规范自定义的一个名称;如果有多个重定向文件(.o)怎么办,末尾继续追加就可】这样就得到了名为libadd.a的库函数。如图:

             动态库:将myadd.c打包成动态库

            a.gcc  -shared -fPIC  -o libadd.so  myadd.c 【-shared表示生成动态库,fPIC为参数,libadd.so为动态库的命名规范,myadd.c表示要编译的源文件,如果有多个源文件要同时编译问一个动态库,直接后面追加即可】一步到位,就是这么简单,来看看生成的文件,如图:

     通过上述过程,我们知道了如何将原文件打包为库文件,有了库文件我么如何使用呢?

            (4)如何使用库?

            我们的函数入口为main.c,里面我们调用了加法add函数,现在我么就可以不依靠myadd.c来编译代码了,因为myadd.c被编译成了库函数。现在我们删除myadd.c和myadd.o,中保留主函数,头文件和库函数,来看看如何利用库函数来编译主函数的?

            编译命令:gcc main.c -o main -I ./ -L ./ -ladd 【-I 表示头文件的路径名,头文件在同一路径,所以使用./代替,-L表示库的路径,这里也在当前路径下,所以也使用./,最后的-ladd,其中l是必须的表示需要的库,add表示去掉前缀lib和后缀.so或者.a后的库名,不能分开书写】执行后即可生成main可执行文件。

            【注意!】因为无论是使用静态库编译或者使用动态库编译我们都是使用的同一命令,所以在编译的时候最好是先将一个库拷贝出来,让这个目录下只含有一个库,或者说将其中一个放到其它文件下,我们使用-L 时加上相对路径就好。通过以上操作,我们就使用库编译好了可执行的二进制文件,现在,如果你是编译的静态库,你就可以只保留可执行的二进制文件,然后就可以正常运行了,但是,如果你是编译的动态库的话,你会发现运行的时候就会失败,这是为什么呐?这是因为,我们说过,使用静态库编译是在编译时就将源文件和库一起编译,生成可执行的二进制文件,固然它是可以独立运行的;但是,动态库是在运行时才会去加载[注意,我们编译生成二进制文件时也需要动态库的支持,而且它加载的路径是在/usr/lib或者/lib/目录下,当程序运行的时候,就会去这两个路径下去找对应的动态库了,所以我们将他拷贝到这两个目录的其中一个就可以运行了。此外,还可以添加环境变量的方式,将库放在任何目录下,这里不建议这样做,但是还是说一下,我们只需要向bashrc的末尾添加 export LD_LIBRARY_PATH=动态库的绝对路径   然后保存重启或者使用source一下就可以了,这样以后去搜索库时,除了搜索/usr/lib/,/lib/目录下,还会搜索我们刚刚添加的这个路径,这样的操作是永久生效的,如果你是想临时验证,直接执行 export LD_LIBRARY_PATH=动态库的绝对路径  这个命令就好了,如果你不知道环境变量,或者source这些概念,甚至你还不会linux基本命令,那么就需要补一下这方面的知识了。通过上面的操作,我们使用动态库编译的程序就可以运行了,现在,如果你需要升级,更改了函数实现,比如将加法里面再添加一句打印,你想想,是不是直接修改后提供给用户新的库就好了,而不需要向用户提供整个可执行文件了。


     4.总结

            前面我么说了这么多,总的来说还算详细,如果你还 遇到了其它问题,欢迎评论区和各位探讨。现在,我么们总结一下前面说的:

            (1)什么时候需要头文件:当我们使用某个库中的函数,结构体或者变量等,我么就需要使用头文件。这个头文件可以是C语言标准中实现的,也可以是自己实现的。

            (2)如何自定义头文件,以及定义头文件时的注意事项:自定义头文件时要在原文件中引入自己的头文件,这样在编译阶段,会检测到函数的声明和定义是否一致,防止错误发生在运行时阶段。头文件要有ifndef,define等条件编译的宏,这是为了防止重复定义。此外要知道头文件中不要出现函数的具体实现,只能是函数声明,宏,结构体,联合体,变量,枚举,还有内联函数,这是一种规范。

            (3)动态库和静态库:我们介绍了头文件的一些知识点,就牵涉到了我们如何将自己写的函数打包成库,这里我们需要知道库的种类,使用库和直接使用源文件有何不同,要清楚库的编译方式以及如何去使用它们。

           好了,说到这就结束了,我们江湖见。

      

    展开全文
  • 【例1.2】#include#includemain(){double x,s;printf("input number:\n");...} include称为文件包含命令 扩展名为.h的文件称为头文件 定义两个实数变量,以被后面程序使用 显示提示信息 从键盘获得一个...
  • matlab将数据保存到c语言头文件.h中
  • C语言自定义头文件

    千次阅读 2021-05-31 17:30:19
    一些初学C语言的人,不知道头文件(*.h文件)原来还可以自己写的。只知道调用系统库函数时,要使用#include语句将某些头文件包含进去。其实,头文件跟.C文件一样,是可以自己写的。头文件是一种文本文件,使用文本...
  • C语言头文件详解

    千次阅读 2020-06-26 21:43:06
    C语言头文件详解 引言 在C语言家族程序中,头文件被大量使用。一般而言,每个C++/C程序通常由头文件(header files)和定义文件(definition files)组成。头文件作为一种包含功能函数、数据接口声明的载体文件,主要...
  • C语言编写头文件

    万次阅读 多人点赞 2019-05-10 23:20:57
    通常我们写C程序时,都会直接使用这样的语句“#include <...2,头文件可以定义很多宏定义,就是一些全局静态变量的定义,在这样的情况下,只要修改头文件的内容,程序 就可以做相应的修改,不用亲自...
  • C语言头文件的使用

    2022-03-18 19:55:42
    标准头文件写法 先了解一下什么是条件编译 //条件编译结构 #if 0或1 //代码块 #endif 那如何使用呢? #if 1 //值为1则编译框中代码 int main(int argc, const char *argv[]) { return 0; } #endif #if 0 //值...
  • C语言头文件大全

    2021-05-22 10:35:41
    cC系统提供了丰富的系统文件,称为库文件,C的库文件分为两类,一类是扩展名为".h"的文件,称为头文件,在前面的包含命令中我们已多次使用过。在".h"文件中包含了常量定义、 类型定义、宏定义、函数原型以及各种编译...
  • c语言头文件的-函数-全局变量
  • C语言头文件

    千次阅读 2021-11-14 21:32:22
    C语言头文件
  • C语言头文件的用法及注意事项

    千次阅读 2021-08-24 20:26:05
    本文主要介绍一下头文件的用法以及在使用头文件时该注意的一些细节 一、头文件的内容 头文件应该包含一下内容: 1、头文件卫士 2、声明外部变量、函数、类、结构、联合、枚举 3、定义宏、类型别名 4、包含其它...
  • C语言基础:C语言头文件

    千次阅读 多人点赞 2020-06-22 19:20:29
    本文从Simulink生成的代码出发,研究C语言头文件的作用。 文章目录1 头文件的作用2 C文件中引用头文件3 头文件的内容 1 头文件的作用 博主理解,头文件的作用可以归纳为一句话,那就是把各个C文件联系起来。 至于...
  • C语言头文件下载

    千次阅读 2021-05-20 02:52:27
    传统 C++#include <assert.h> //设定插入点#include <ctype.h> //字符处理#include <errno.h> //定义错误码#include <float.h> //浮点数处理#include <fstream.h>...
  • 在自身写C实现二叉树时所写的队列的实现代码,内附代码和头文件,在头文件中修改 QueueType 的define还有 InputQueue 函数就可以适配其余功能例如其他结构体。 初始QueueTpye 为int型
  • comm.h和comm.c是公共模块。 test1.h和test1.c使用了公共模块。 test2.h和test2.c使用了了公共模块。 test.h和test.c使⽤用了了...将头文件放在“头文件” ifndef __TEST_H__ #define __TEST_H__ //头文件 #endif ...
  • c语言头文件头文件中一般放一些重复使用的代码,例如函数声明,变量声明,常数定义,宏的定义等等。当使用#include语句将头文件引用时,相当于将头文件中所有内容,复制到#include处。为了避免因为重复引用而导致...
  • C语言头文件的导入

    千次阅读 2020-03-15 10:10:06
    首先,对于很多萌新编程者,把所有函数...首先我们创建一个简单的C语言函数,并且导入我们字节写的头文件。以下为头文件以及保存方式: 以上为我们的头文件,里面需要包括导入的库函数、宏定义以及我们所定义的函数...
  • 如何写C语言头文件

    2018-10-02 16:49:18
    这是一篇简单明了的介绍C语言中如何编写头文件的文章。
  • c语言头文件编写方法

    2014-09-23 20:11:56
    在编写C程序的时候,如果功能比较多,一般都会使用模块化编写方法,使程序更加容易... 使用模块化程序的话,少不了头文件。 附件是详细介绍头文件的写法。 文件加上我的一点实践后得出的经验。 对于新手,非常有用。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 190,402
精华内容 76,160
关键字:

c语言下载头文件