精华内容
下载资源
问答
  • 2021-01-19 14:18:27

    C语言基础专题 - 头文件引用


    jcLee的个人博客:https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343

    邮箱:291148484@163.com

    本文地址https://blog.csdn.net/qq_28550263/article/details/112790154

    本文介绍了C语言中头文件的引用方法
    阅读本文前推荐阅读C语言预处理


    目 录

    1.🧐什么是头文件?
    2.🧐如何引用头文件?
    3.🧐头文件中有一般写了什么?
    4.👨‍🏫条件引用
    5.👨‍🏭用宏定义确保单次引用


    1.🧐什么是头文件?

    头文件是扩展名为 .h 的文件,这是一个文本文件,内容包含了:

    2.🧐如何引用头文件?

    这个事情我们所有人写的第一个程序Hello World.c中都做过:

    #include <stdio.h>     // 引用头文件
    int main(){
       printf("Hello World")
    }
    

    这里被引用的头文件stdio.h它是编译器自带的,属于系统头文件。
    我们不但可以引用系统头文件,也可以引用自己写的头文件,即用户头文件,但这再语法上由略微差别:

    #include <file>    //  用于引用名为file的系统头文件,默认在系统目录的标准列表中搜索该文件
    #include "file"     //  用于引用名为file的用户头文件 ,默认在包含当前文件的目录中搜索该文件
    

    C语言的编译器有很多,对于以上两种使用头文件的方法一般都提供了相关选项以加入搜索头文件的路径,也常有在名为INCLUDE环境变量中加入搜索路径,以告诉编译器头文件的位置。

    比如,在GCC中(以下引用内容摘录自GCC官方文档3.16目录搜索的选项章节,有外语基础的读者可以自行阅读。)

    这些选项指定目录以搜索头文件,库和编译器的一部分:

    -I dir
    -iquote dir
    -isystem dir
    -idirafter dir
    

    它们在预处理(可以参考C语言预处理部分内容)的时候将目录dir添加到要在预处理过程中搜索头文件的目录列表中。如果dir以'='或>$SYSROOT,然后是'='或被$SYSROOTsysroot前缀替换;看到 --sysroot->isysroot

    指定的目录 -I 引用仅适用于指令的引号形式。指定的目录#include "file" -I-isystem,或者 -idirafter适用于 #include "file"#include <file>指令的查找 。
    您可以在命令行上指定任何数目或这些选项的组合,以在多个目录中搜索头文件。查找顺序如下:

    • (1)对于include指令的引号形式,将首先搜索当前文件的目录。
    • (2)对于include指令的引号形式,目录由 -我引用 选项在命令行中按从左到右的顺序搜索。
    • (3)指定目录 -I 选项以从左到右的顺序扫描。
    • (4)指定目录 -isystem 选项以从左到右的顺序扫描。
    • (5)扫描标准系统目录。
    • (6)指定目录 -idirafter 选项以从左到右的顺序扫描。

    您可以使用 -I覆盖系统头文件,替代您自己的版本,因为这些目录是在标准系统头文件目录之前搜索的。但是,您不应使用此选项来添加包含供应商提供的系统头文件的目录。采用-isystem为了那个原因。
    -isystem-idirafter 选项还将该目录标记为系统目录,以便对它进行与标准系统目录相同的特殊处理。

    如果标准系统包含目录,或使用以下命令指定的目录 -isystem,也指定了 -I-I 选项将被忽略。该目录仍在搜索,但作为系统目录位于系统包含链中的正常位置。这是为了确保#include_next不会错误地更改GCC修正错误的系统头的过程以及该指令的顺序。如果您确实需要更改系统目录的搜索顺序,请使用-nostdinc 和/或 -isystem 选项。

    3.🧐头文件中有一般写了什么?

    如果想自己写一个头文件,那还是有必要了解一下头文件的内容的。我们不妨先打开我们从写HelloWorld.c就开始使用的stdio.h一探究竟。

    /* Checking macros for stdio functions.
       Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
    
    This file is part of GCC.
    
    GCC is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License as published by the Free
    Software Foundation; either version 3, or (at your option) any later
    version.
    
    In addition to the permissions in the GNU General Public License, the
    Free Software Foundation gives you unlimited permission to link the
    compiled version of this file into combinations with other programs,
    and to distribute those combinations without any restriction coming
    from the use of this file.  (The General Public License restrictions
    do apply in other respects; for example, they cover modification of
    the file, and distribution when not linked into a combine
    executable.)
    
    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    for more details.
    
    Under Section 7 of GPL version 3, you are granted additional
    permissions described in the GCC Runtime Library Exception, version
    3.1, as published by the Free Software Foundation.
    
    You should have received a copy of the GNU General Public License and
    a copy of the GCC Runtime Library Exception along with this program;
    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    <http://www.gnu.org/licenses/>.  */
    
    
    #ifndef _SSP_STDIO_H
    #define _SSP_STDIO_H 1
    
    #include <ssp.h>
    #include_next <stdio.h>
    
    #if __SSP_FORTIFY_LEVEL > 0
    
    #include <stdarg.h>
    
    #undef sprintf
    #undef vsprintf
    #undef snprintf
    #undef vsnprintf
    #undef gets
    #undef fgets
    
    extern int __sprintf_chk (char *__restrict__ __s, int __flag, size_t __slen,
    			  __const char *__restrict__ __format, ...);
    extern int __vsprintf_chk (char *__restrict__ __s, int __flag, size_t __slen,
    			   __const char *__restrict__ __format,
    			   va_list __ap);
    
    #define sprintf(str, ...) \
      __builtin___sprintf_chk (str, 0, __ssp_bos (str), \
    			   __VA_ARGS__)
    #define vsprintf(str, fmt, ap) \
      __builtin___vsprintf_chk (str, 0, __ssp_bos (str), fmt, ap)
    
    extern int __snprintf_chk (char *__restrict__ __s, size_t __n, int __flag,
    			   size_t __slen, __const char *__restrict__ __format,
    			   ...);
    extern int __vsnprintf_chk (char *__restrict__ __s, size_t __n, int __flag,
    			    size_t __slen, __const char *__restrict__ __format,
    			    va_list __ap);
    
    #define snprintf(str, len, ...) \
      __builtin___snprintf_chk (str, len, 0, __ssp_bos (str), __VA_ARGS__)
    #define vsnprintf(str, len, fmt, ap) \
      __builtin___vsnprintf_chk (str, len, 0, __ssp_bos (str), fmt, ap)
    
    extern char *__gets_chk (char *__str, size_t);
    extern char *__SSP_REDIRECT (__gets_alias, (char *__str), gets);
    
    extern inline __attribute__((__always_inline__)) char *
    gets (char *__str)
    {
      if (__ssp_bos (__str) != (size_t) -1)
        return __gets_chk (__str, __ssp_bos (__str));
      return __gets_alias (__str);
    }
    
    extern char *__SSP_REDIRECT (__fgets_alias,
    			     (char *__restrict__ __s, int __n,
    			      FILE *__restrict__ __stream), fgets);
    
    extern inline __attribute__((__always_inline__)) char *
    fgets (char *__restrict__ __s, int __n, FILE *__restrict__ __stream)
    {
      if (__ssp_bos (__s) != (size_t) -1 && (size_t) __n > __ssp_bos (__s))
        __chk_fail ();
      return __fgets_alias (__s, __n, __stream);
    }
    
    #endif /* __SSP_FORTIFY_LEVEL > 0 */
    #endif /* _SSP_STDIO_H */
    

    可以看到:

    • 写在最前边的一般是文件内容概述(该文件为检查标准函数的宏(Checking macros for stdio functions.))、版权说明等。
    • 对于程序预处理与之后编译实质内容时后面的c代码,这些代码一般是从以前中写在源文件最前面(头部)的位置,我们将这些代码摘出来,因此叫做头文件。
    • 该文件中还引入了大量其它的头文件。
    • 除此之外我们还看到了大量的extern有关的语句,extern用于调用另一个c文件里的变量或者函数。

    4.👨‍🏫条件引用

    更多相关指令可以参考:C语言-预处理

    这里我们先了解下面这几条预处理指令:

    指令说明
    #if如果给定条件为真,则执行预处理的内容
    #else表示#if后的条件为假时执行预处理的内容
    #elif如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码
    #endif结束一个 #if……#else 条件编译块
    比如:
    #if CONDITION_1              // 若第1个条件成立
       # include "headfile_1.h"  // 引入头文件"headfile_1.h"
    #elif CONDITION_2            // 若第2个条件成立
       # include "headfile_2.h"  // 引入头文件"headfile_2.h"
       ...
    #endif                       // 条件指令的结束
    

    5.👨‍🏭用宏定义确保单次引用

    在C语言中提供了以下两个指令:

    指令说明
    #ifdef如果宏已经定义,则返回真
    #ifndef如果宏没有定义,则返回真
    为了防止由于多次头文件多次引用导致某些情况下产生错误,我们需要使用上面两个指令。请看代码:
    #ifndef A                        //  当没有宏定义A时
    #define A  包含所有头文件的文件B   // 宏定义A为包含所有头文件的文件B 
    #endif                           // 用于结束一个 #if……#else 条件编译块
    

    为了防止意外,而把头文件的内容都放在#ifndef#endif指令块中。这样作无论头文件会不会被多个文件引用,也就是当再次引用到头文件HeadFileB时,条件为假。

    更多相关内容
  • 如下图,在编译时大量报出语法错误,检查又没有明显错误 后来发现其实是typedof定义出错。在typedof里定义指针前面一定要加“struct”!(亲测,只需加上这里其他地方无需改动)。分析应该是该结构...

    最近在学数据结构时出现的问题

    如下图,在编译时大量报出语法错误,检查时又没有明显错误

    后来发现其实是typedof定义时出错。在typedof里定义指针时前面一定要加“struct”!(亲测,只需加上这里其他地方无需改动)。分析应该是该结构未定义完又引用该结构指针而出错

    加上后就正常了

    哎应该是太久没用c语言了吧忘了这个了。希望能帮到你

    展开全文
  • 这是因为,如有2个头文件a.h和 b.h,A.h有#include “B.h”,而b.h也有#include"A.h",同时B.h...A.h与B.h之间无限循环引用,即会导致以上的错误。解决方法是在B.h头文件的类前声明一下A类即可(即class A;)。 ...

    在这里插入图片描述
    这是因为,如有2个头文件a.h和 b.h,A.h有#include “B.h”,而b.h也有#include"A.h",同时B.h头文件中有a类的对象(即有A a)等,这样造成

    A.h与B.h之间无限循环引用,即会导致以上的错误。解决方法是在B.h头文件的类前声明一下A类即可(即class A;)。

    展开全文
  • 这是因为,如有2个头文件a.h和 b.h,A.h有#include “B.h”,而b.h也有#include"A.h...A.h与B.h之间无限循环引用,即会导致以上的错误。解决办法也很简单,只需要在B.h头文件的类前声明一下A类即可(即class A;)。 ...

    在这里插入图片描述
    这是因为,如有2个头文件a.h和 b.h,A.h有#include “B.h”,而b.h也有#include"A.h",同时B.h头文件中有a类的对象(即有A a)等,这样造成

    A.h与B.h之间无限循环引用,即会导致以上的错误。解决方法是在B.h头文件的类前声明一下A类即可(即class A;)。

    展开全文
  • 随着代码越写越长,一个源文件的体制越来越臃肿。于是提倡将代码写到不同的多个源文件中去。...当某一.c源文件需要调用某一函数的时候,只要将包含这个函数声明的头文件包含到本文件中来就可以了。如a.h...
  • 怎样在C语言中用H头文件声明一个外部struct变量要定义一个struct变量,首先要定义一个结构体变量类型名 即struct结构体名例如定义一个按键属性结构体(包含 是否有按键值更新(renew)和按键值(num)两个成员)struct Key...
  • **头文件加入stdlib.h后显示语法错误无法运行** #include #include int max(int x,int y); int main () { int a,b,c; scanf ("%d,%d",&a,&b); c = max (a,b); printf ("max = %d\n",c); system (...
  • C语言头文件的作用

    千次阅读 多人点赞 2018-08-23 00:54:40
    C语言头文件的作用 最近在工作当中遇到了一点小问题,关于C语言头文件的应用问题,主要还是关于全局变量的定义和声明问题.学习C语言已经有好几年了,工作使用也近半年了,但是对于这部分的东西的确还没有深
  • 例如,编译源文件需要用到头文件B,且源文件已包含头文件A,而索性将头文件B包含在头文件A中,这是错误的做法。 4)尽量保证用户使用此头文件时,无需手动包含其他前提头文件,即此头文件内已包含前提头文件。 ...
  • C++std命名空间和头文件详解

    千次阅读 多人点赞 2020-05-07 20:16:44
    例如小李和小韩都参与了一个文件管理系统的开发,它们都定义了一个全局变量 fp,用来指明当前打开的文件,将他们的代码整合在一起编译,很明显编译器会提示 fp 重复定义(Redefinition)错误。 为了解决合作开发.....
  • 今天在看Leveldb源码的时候,发现作者使用了很多前置声明,这个语法之前关注的...我看leveldb源码的时候,作者大量使用前置声明,并不是因为这个原因,忘了在哪看到过,在此处使用前置声明的原因应该是:前置 引用声明
  • c头文件

    2017-05-19 18:22:32
    最近在工作当中遇到了一点小问题,关于C语言头文件的应用问题,主要还是关于全局变量的定义和声明问题. 学习C语言已经有好几年了,工作使用也近半年了,但是对于这部分的东西的确还没有深入的思考过.概念上还是比较模糊...
  • 例如:要编写头文件test.h  在头文件开头写上两行:  #ifndef _TEST_H  #define _TEST_H//一般是文件名的大写  ············  ············  头文件结尾写上一行:...
  • 这是因为函数模板要被实例化后才能成为真正的函数,在使用函数模板的源文件中包含函数模板的头文件,如果该头文件中只有声明,没有定义,那编译器无法实例化该模板,最终导致链接错误。 C语言struct和C++struct区别...
  • 华为C语言编程规范(精华总结)

    万次阅读 多人点赞 2020-03-24 09:48:55
    通常的手段是为每个文件配置一个宏,当头文件第一次被包含就定义这个宏,并在头文件被再次包含使用它以排除文件内容。所有头文件都应当使用#define 防止头文件被多重包含,命名格式为FILENAME_H,为了保证唯一性...
  • 本文将尽量详细的介绍c语言的头文件所包含的知识,如有错误,还望指正。 萌新们肯定疑惑为什么每次打代码都要写一个所谓的头文件(如:#include<stdio.h>),这里先简单让大家有个了解,你所用的 printf("%d",...
  • 突然翻到2019年的笔记本,看了一下自己所做的笔记,列举着一些Qt和 VS开发的一些常见错误分析以及相关解决方法,突然就想放在csdn上,便于查看,毕竟笔记本容易掉,放着放着就不知道放哪儿去了 ,虽然随着开发时间的...
  • 1 extern extern关键字用来声明变量或者函数是一个外部变量或者外部函数,也就是说告诉编译器该...,那么在其他文件中的函数调用变量a的时候需要在对应头文件或者定义文件中(保证在使用这个变量前)使用extern i...
  • http://jingpin.jikexueyuan.com/article/38309.html 语言头文件组织与包含原则 作者: clover_toeic ...发布时间:2015-07-07 16:38:58 ... 如非特殊说明,文中“源文件”指*.c文件,“头文件”指
  • 而在编译过程中出现报错,错误代号是error C2065 : 未声明的标识符,我的第一反应是为什么我没通过手动添加资源而是通过VS添加都会出现这种情况呢,我想应该是其它地方错误导致此报错吧,但是却没想过,此类错误往往是...
  • C++基础语法面试题

    千次阅读 2020-06-10 17:11:15
    C++基础语法面试题 malloc/free和new/delete的区别 int *p; p = (int*)malloc(sizeof(int) * 128); //分配128个(可根据实际需要替换该数值)整型存储单元, //并将这128个连续的整型存储单元的首地址存储到指针变量...
  • C头文件组织与包含原则

    千次阅读 2017-09-04 20:33:01
     如非特殊说明,文中“源文件”指*.c文件,“头文件”指*.h文件,“引用”指包含头文件。   一、头文件作用  C语言里,每个源文件是一个模块,头文件为使用该模块的用户提供接口。接口指一个功能模块...
  • 例如:要编写头文件test.h  在头文件开头写上两行:  #ifndef _TEST_H  #define _TEST_H//一般是文件名的大写  ············  ············  头文件结尾写上一行:  #endif ...
  • 例如:要编写头文件test.h  #ifndef _TEST_H  #define ... _TEST_H//一般是文件名的大写 ... 1.比如你有两个C文件,这两个C文件都include了同一个头文件。而编译,这两个C文件要一同编译成
  • 关于头文件中的理解

    2015-04-18 08:56:35
    头文件的重复包含和编译
  • ,就会出现大量“重定义”的错误。在头文件中实用#ifndef #define #endif能避免头文件的重定义。 方法:例如要编写头文件test.h 在头文件开头写上两行: #ifndef _TEST_H #define _TEST_H//一般是文件名的大写
  • Makefile的语法

    千次阅读 2020-05-03 22:25:28
     所有时间戳比目标文件晚的依赖文件,并以空格分开 $@ 目标文件的完整名称 $^ 所有不重复的目标依赖文件,以空格分开 -: 告诉make命令忽略所有的错误 @: 告诉make在执行命令前不要将改命令显示在标准输出上,...
  • c/c++头文件的作用

    2016-03-12 23:38:28
    C语言中的.h文件和我认识由来已久,其使用方法虽不十分复杂,但我却是经过了几个月的“不懂”时期,几年的“一知半解”时期才逐渐认识清楚他的本来...原因二:现在的各种C语言书籍都是只对C语言的语法进行详细的不能
  • 例如:要编写头文件test.h   在头文件开头写上两行:   #ifndef _TEST_H   #define _TEST_H//一般是文件名的大写   ············  ············   头文件结尾写上一行:  #endif...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,094
精华内容 5,637
关键字:

引用头文件时大量语法错误