【C/C++】引号和尖括号的区别|默认include路径配置|头文件应放些什么|static和extern

本文详细解释了C/C++中使用尖括号与双引号进行头文件包含的区别,介绍了如何设置默认的include路径,并探讨了static与extern关键字在函数声明中的作用,以及头文件的重要性和正确使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 引号和尖括号区别

默认include路径设置

查看添加结果

关于static和extern、头文件的一点总结。

头文件中应该放些什么2


引号和尖括号区别

用尖括号 #include <>:
一般用于包含标准的库头文件,编译器会去系统配置的库环境变量和者用户配置的路径去搜索,而不会在项目的当前目录去查找
用双引号 #include "":
一般用于包含用户自己编写的头文件,编译器会先在项目的当前目录查找,找不到后才会去系统配置的库环境变量和用户配置的路径去搜索

一、引用的头文件不同

#include< >引用的是编译器的类库路径里面的头文件。

#include“ ”引用的是你程序目录的相对路径中的头文件。

二、用法不同

#include< >用来包含标准头文件(例如stdio.hstdlib.h).

#include“ ”用来包含非标准头文件。

三、调用文件的顺序不同

#include< >编译程序会先到标准函数库中调用文件。

#include“ ”编译程序会先从当前目录中调用文件。

四、预处理程序的指示不同

#include< >指示预处理程序到预定义的缺省路径下寻找文件。

#include“ ”指示预处理程序先到当前目录下寻找文件,再到预定义的缺省路径下寻找文件。  

参考:#include中尖括号和双引号的区别_路人王_Zz的博客-优快云博客_include引号和尖括号的区别

默认include路径设置

除了默认的/usr/include, /usr/local/include等include路径外,还可以通过设置环境变量来添加系统include的路径:

# C
export C_INCLUDE_PATH=XXXX:$C_INCLUDE_PATH
# CPP
export CPLUS_INCLUDE_PATH=XXX:$CPLUS_INCLUDE_PATH

以上修改可以直接命令行输入(临时),也可以写入文件:写入/etc/profile中(对所有用户生效),也可以在用户home目录下的.bashrc或.bash_profile中添加(针对某个用户生效),修改完后重新登录shell即生效。

查看添加结果

对于C

echo | gcc -v -x c -E -

对于C++

echo | g++ -v -x c++ -E -  或者  echo | gcc -v -x c++ -E -

修改gcc/g++默认include路径_weixin_34337265的博客-优快云博客

其他:

2011关于static和extern、头文件的一点总结。

关于static和extern、头文件的一点总结。 【转】

今天写了一个测试程序。突然想起了几个问题。特地测试了一下:

主程序为testemail.c

        #include<stdio.h>

      2 #include<stdlib.h>

      3 #include<string.h>

      4 #include "system.h"

      5 

      6 

      7 int main(int argc,char ** argv)

      8 {

      9          int ret;

     10         NET_EMAIL  getmail ;

     11         NET_EMAIL * pgetmail = &getmail;

     12         strcpy(pgetmail->SendAddr,"root@localhost.localdo");

     13         strcpy(pgetmail->Sendername,"");

     14         strcpy(pgetmail->Title,"meinv");

     15         strcpy(pgetmail->Recievers,"intermilan@yeah.net,mm@yer.cn,4393@qq.com");

     16         strcpy(pgetmail->path,"/var/log/messages");

     17         SendEmail(pgetmail);

     18         print();

     19 }

头文件为system.h

里面声明了NET_EMAIL这种结构体。也声明了SendEmail和print这两个函数。

被测试程序为system.c里面实现了SendEmail和print

测试结果如下:

1.即使不在system里声明函数SendEmail和print,只要system.c和testemail在同一个目录下。

总是能够编译通过并且可以成功运行。-------这说明函数默认的性质为extern的。

2.当system.c里声明两个函数关键字为static的时候,编译就会报错。可见static的作用是限制函数

只能在该文件内被引用。

那么问题出现了。这样的话,某种意义上来说头文件有什么用呢?

经过查找资料和测试如下

1.很多商业代码不会提供给客户源码。比如这个system.c在真正用的时候,可能会编译成system.o的形式提供给客户,

给其它的程序开发人员来调用。这样的话,如果没有system.h,其它的程序员怎么知道有SendEmail这个函数,即便

知道,怎么精确的知道用法和参数?所以这个时候头文件就起到了说明书的作用了。

2.测试当system.h里没有SendEmail的时候,即便在testemail.c里调用SendEmail的时候,给它一个不合法的参数,发

现编译仍然可以通过,但是真正运行的时候就出现了段错误。这样的话会给排除BUG带来困难。因此这个时候头文件

起到了类型安全检查的作用。

所以可以有以下的总结:

1.所谓源文件就是单个.c文件。所谓工程就是同一个目录下的所有文件。

2.不想让其它.c文件访问的函数一定要加上static关键字。其他的函数虽然不在头文件里声明也可以被访问到,但是为了

类型安全检查我们也要最好在头文件里声明。写头文件就像写说明书一样。要养成好的编程风格

2011头文件中应该放些什么2

头文件中应该放些什么2
作者:佚名  来源:不详  录入:Admin  更新时间:2008-8-17 19:38:48  点击数:3
【字体: 】
作为一般规则, 应该把这些东西放入头 (.h) 文件中:
  • 宏定义 (预处理 #defines)
  • 结构、联合和枚举声明
  • typedef 声明
  • 外部函数声明
  • 全局变量声明

当声明或宏定义需要在多个文件中共享时, 尤其需要把它们放入头文件中。特别是, 永远不要把外部函数原型(即外部函数声明)放到 .c 文件中。

另一方面, 如果宏定义或声明为一个 .c 文件私有, 则最好留在 .c 文件中。

头文件中应该放些什么2
作者:佚名  来源:不详  录入:Admin  更新时间:2008-8-17 19:38:48  点击数:3
【字体: 】
作为一般规则, 应该把这些东西放入头 (.h) 文件中:
  • 宏定义 (预处理 #defines)
  • 结构、联合和枚举声明
  • typedef 声明
  • 外部函数声明
  • 全局变量声明

当声明或宏定义需要在多个文件中共享时, 尤其需要把它们放入头文件中。特别是, 永远不要把外部函数原型(即外部函数声明)放到 .c 文件中。

另一方面, 如果宏定义或声明为一个 .c 文件私有, 则最好留在 .c 文件中。

头文件中应该放些什么2
作者:佚名  来源:不详  录入:Admin  更新时间:2008-8-17 19:38:48  点击数:3 
【字体:     】
 
 
作为一般规则, 应该把这些东西放入头 (.h) 文件中:
宏定义 (预处理 #defines)
结构、联合和枚举声明
typedef 声明
外部函数声明
全局变量声明
当声明或宏定义需要在多个文件中共享时, 尤其需要把它们放入头文件中。特别是, 永远不要把外部函数原型(即外部函数声明)放到 .c 文件中。

另一方面, 如果宏定义或声明为一个 .c 文件私有, 则最好留在 .c 文件中。
 

 

<think>好的,我需要帮助用户在Keil MDK中添加自定义头文件并正确引用,而不仅仅是配置路径。用户之前的问题已经涉及路径设置,现在他们想了解其他可能导致编译错误的原因。 首先,回顾之前的回答,我提到了头文件保护、声明与定义分离、源文件包含头文件、避免循环依赖、语法检查等。现在用户引用了一个关于添加源文件头文件到工程的方法,但用户明确指出不需要路径配置,而是如何正确添加引用头文件本身。 我需要明确,添加头文件到工程设置包含路径不同。Keil中头文件通常不需要像源文件那样添加到工程里,只要路径正确,编译器就能找到。但用户可能误解了添加头文件到工程的必要性,或者他们可能想确保头文件被正确包含在项目中。 可能的步骤包括: 1. **头文件是否必须添加到工程中?** 通常不需要,但添加可能有助于项目管理。 2. **如何在工程中添加头文件?** 用户引用的方法提到通过Add Existing Files,但这是否必要? 3. **正确引用头文件的语法问题**,比如使用#include "header.h"而不是#include <header.h>。 4. **检查头文件内容**,如保护宏、声明与定义分离,避免重复定义。 另外,用户可能遇到的问题是头文件虽然路径正确,但内容有误,导致编译错误。例如,未加保护宏导致重复包含,或者在头文件中定义变量导致多重定义。 需要强调头文件的内容规范引用方式,而不仅仅是添加到工程。可能还需要说明,即使头文件不在工程中,只要路径正确且内容正确,也能被正确编译。但添加头文件到工程可能有助于IDE中的导航查看。 最后,确保回答结构清晰,分步骤说明,并包含常见错误解决方案,帮助用户系统地解决问题。</think>#### **如何在Keil MDK中添加自定义头文件并正确引用(非路径配置)** 若已正确配置头文件路径但编译仍报错,问题通常集中在头文件的内容规范、工程结构管理及代码引用方式上。以下是具体操作关键注意事项: --- ### **一、头文件是否需显式添加到工程?** Keil MDK **不要求头文件必须添加到工程**中,只要其路径已包含在编译器的搜索路径(`Include Paths`)中,编译器即可自动检索。但以下情况建议显式添加头文件到工程: - **代码导航需求**:方便在IDE中快速查看编辑头文件。 - **版本管理**:确保工程内文件结构清晰,与版本控制系统同步。 #### **添加头文件到工程的方法** 1. **通过“Add Existing Files”直接添加**: - 右键点击工程中的目标组(如`Source Group`)→ 选择 `Add Existing Files to Group...`。 - 在文件选择对话框中,将文件类型过滤器改为 `All Files (*.*)`,选中需要添加的 `.h` 文件 → 点击 `Add`。 - **注意**:此操作仅将头文件加入工程列表,**不替代路径配置**,仍需确保其目录已包含在 `Include Paths` 中[^1]。 2. **使用“Manage Project Items”管理**: - 右键工程名 → 选择 `Manage Project Items` → 在 `Project Items` 标签页中,选择目标组 → 点击 `Add Files` 添加头文件。 --- ### **二、头文件内容规范(避免编译错误的核心)** #### 1. **强制使用头文件保护宏** 头文件重复包含会导致`重复定义`错误。需通过宏保护防止多次展开: ```c // my_header.h #ifndef __MY_HEADER_H__ // 唯一标识符(建议项目名_文件名_H) #define __MY_HEADER_H__ // 函数声明、宏定义、结构体等 #endif ``` #### 2. **严格区分声明与定义** - **禁止在头文件中定义全局变量或函数**: ```c // 错误示例(头文件内) int global_value = 0; // 直接定义全局变量(链接时报错) void init_system(void) { } // 函数实现(多重定义) ``` - **正确做法**: ```c // my_header.h extern int global_value; // 声明全局变量 void init_system(void); // 声明函数 ``` ```c // my_code.c #include "my_header.h" int global_value = 0; // 定义全局变量 void init_system(void) { } // 定义函数 ``` #### 3. **避免在头文件中包含复杂实现** - **仅保留声明简单宏**:头文件中若包含复杂逻辑(如静态函数、模板代码),需确保其仅在当前编译单元有效。 - **内联函数限制**:使用 `static inline` 时,需确认编译器支持且无副作用。 --- ### **三、源文件引用头文件的正确方式** #### 1. **使用双引号 `""` 而非尖括号 `<>`** - **`#include "my_header.h"`**:优先从当前文件目录或工程自定义路径搜索。 - **`#include <stdlib.h>`**:仅从系统/编译器标准路径搜索。 #### 2. **避免循环依赖** 若 `A.h` 依赖 `B.h`,而 `B.h` 又依赖 `A.h`,会导致预处理死循环。解决方案: - **前置声明**:在 `B.h` 中用前置声明替代直接包含 `A.h`。 ```c // B.h struct Device; // 前置声明结构体(无需包含A.h) void configure_device(struct Device* dev); ``` - **在 `.c` 文件中包含依赖**: ```c // B.c #include "A.h" // 实际包含结构体定义 void configure_device(struct Device* dev) { /* 实现 */ } ``` --- ### **四、常见编译错误与解决方案** | **错误类型** | **原因** | **解决方案** | |---------------------------|-----------------------------------|------------------------------------------| | `L6200E: Symbol multiply defined` | 头文件中直接定义全局变量/函数 | 将定义移至 `.c` 文件,头文件仅保留声明 | | `Warning: implicit declaration` | 未包含声明头文件 | 在 `.c` 文件中添加 `#include "xxx.h"` | | `Error: expected ';'` | 头文件中结构体/枚举漏写分号 | 检查所有声明结尾的分号 | | `Error: unknown type name` | 头文件依赖顺序错误 | 调整包含顺序或添加前置声明 | --- ### **五、验证流程** 1. **预处理展开检查**: - 在 `Options for Target → C/C++` 中勾选 `Preprocessor Output`,编译后查看 `.i` 文件,确认头文件展开无误。 2. **隔离编译测试**: - 右键单个 `.c` 文件 → `Translate`,检查是否存在语法错误。 3. **清理后重编译**: - 修改头文件后,执行 `Project → Clean Targets` 清除旧中间文件。 --- **相关问题** 1. 如何在Keil中检查预处理后的头文件展开结果? 2. 头文件中使用 `static` 变量会导致什么问题? 3. 为什么双引号 `""` 尖括号 `<>` 在包含头文件时有区别? 通过规范头文件内容与引用方式,可系统性避免非路径相关的编译错误,确保工程结构清晰可靠[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值