一、入题

  在头文件的书写中,都加入了如下内容:

#ifndef __头文件名_H
#define __头文件名_H #endif

  曾经在书中看到的解释是“防止重复定义”,今天突然想到为什么是这样的解释。

二、测试

  测试文件共三个,两个头文件:head1.h、head2.h,一个C源程序:program.c。

1、头文件没有宏定义的代码实验

① 测试代码

head1.h

unsigned char global[] = "hello world!";  

head2.h

unsigned char global[] = "hello world!"; 

program.c

#include "head1.h"
#include "head2.h"
#include <stdio.h> int main(void)
{
printf("%s\n",global);
return ;
}

② 测试结果

  程序在编译时提示:“重复定义了全局变量global”。

2、头文件含有宏定义的代码实验

① 测试代码

head1.h内容:

#ifndef __HEAD_H
#define __HEAD_H unsigned char global[] = "hello world!"; #endif

head2.h

#ifndef __HEAD_H
#define __HEAD_H unsigned char global[] = "hello world!"; #endif

program.c

#include "head1.h"
#include "head2.h"
#include <stdio.h> int main(void)
{
printf("%s\n",global);
return ;
}

② 测试结果

  程序正常编译、连接,生成可执行文件。

三、原因分析

1、头文件没有宏定义的代码实验

  program.c的预编译结果:

head1.h被替换为:
unsigned char global[] = "hello world!";
head2.h被替换为:
unsigned char global[] = "hello world!";
#include <stdio.h> int main(void)
{
printf("%s\n",global);
return ;
}

  显然,重复定义了global。

2、头文件含有宏定义的代码实验

  program.c的预编译结果:

 head1.h被替换为:
#ifndef __HEAD_H
#define __HEAD_H unsigned char global[] = "hello world!";
#endif head2.h被替换为:
#ifndef __HEAD_H
#define __HEAD_H unsigned char global[] = "hello world!";
#endif #include <stdio.h> int main(void)
{
printf("%s\n",global);
return ;
}

  由于一开始没有定义宏__HEAD_H,所以在2行的时候编译器判断为真,就定义了宏__HEAD_H和全局变量global。

  由于在3行的时候定义了宏__HEAD_H,所以编译器判断10行的条件为假,自然也会将其中的内容忽略掉。结果就是:两个头文件实际上只定义一次宏__HEAD_H和全局变量global,所以编译的时候能正常通过。

三、实际应用中

  比如STM32单片机编程的时候,main.c包含了两个外设头文件stm32f10x_gpio.h、stm32f10x_i2c.h,而这两个头文件又都包含了stm32f10x.h。在main.c的预编译过程中,显然stm32f10x.h要被包含两次。通过“头文件的宏定义#ifndef”就可以解决重复包含引起的重复定义的问题。

头文件的宏定义#ifndef测试的更多相关文章

  1. glibc头文件和宏定义

    头文件没啥好说的,无非就是" "和< >的区别,这估计只要是学过C/C++的人都明白.现在的编译器对头文件的包含顺序没有要求,但老的C实现则不一样.当然,我们现在无需关 ...

  2. C语言的头文件和宏定义详解

    原文链接:https://blog.csdn.net/abc_12366/article/details/79155540

  3. C++头文件为什么要加#ifndef #define #endif

    #ifndef 在头文件中的作用 在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件时 ,就会出现大量“重定义”的错误.在头文件中实用#ifndef #de ...

  4. C 头文件、宏、编译问题

    @2019-02-15 [小记] > C 头文件的防重复包含是针对同一个源文件而言 原因: #include 头文件就是一段代码的拷贝,头文件中若有类型定义等,重复包含就会造成编译错误,若无类型 ...

  5. 头文件为什么要加#ifndef #define #endif

    #ifndef 在头文件中的作用 在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件时 ,就会出现大量“重定义”的错误.在头文件中实用#ifndef #de ...

  6. C++ 包含头文件 和 宏的使用 和 条件编译

    1 #define命令剖析 1.1   #define的概念     #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本. ...

  7. extern 用法,全局变量与头文件(重复定义)

    转自 https://www.cnblogs.com/chengmin/archive/2011/09/26/2192008.html 当你要引用一个全局变量的时候,你就要声明,extern int  ...

  8. [转]避免头文件重复包含以及#ifndef 与 #program once 的区别

    为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifndef方式,一种是#pragma once方式.在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一 ...

  9. Cmake 脚本对项目输出路径和输出头文件的路径定义

    对Lib项目的统一输出路径以下时解决方案: set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Lib)set(CMAKE_LIBRARY_O ...

随机推荐

  1. iOS 中UI控件的各种对齐方式总结

    1.textAligment : 文字的水平方向的对齐方式 取值 NSTextAlignmentLeft      = 0,    // 左对齐 NSTextAlignmentCenter    = ...

  2. 基于x86架构的内核Demo的详细开发文档

    http://hurlex.0xffffff.org/ 这里是hurlex这个基于x86架构的内核Demo的详细开发文档, 包含PDF文档和生成PDF的XeLaTex源码和文档每章节的阶段代码. 你可 ...

  3. spinner中的onNothingSelected方法到底什么时候调用?

    这个东东大家在开发中可能不太能用到,所以总是容易被忽略,由于工作原因,我最近琢磨了一下onNothingSelected方法的调用时机问题,其实很简单,只要我们稍微看一下源码就明白了: /** * C ...

  4. Java基础知识强化之IO流笔记42:IO流总结(图解)

    1. IO流总结(图解)

  5. iOS多线程开发--NSThread NSOperation GCD

    多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势 ...

  6. JavaScript跨域解决办法

    在找到跨域解决办法之前,我们要先弄清楚一些基本概念 什么是跨域? 什么是“同源策略”? 跨文档消息通信 & 跨域请求数据 主域相同而子域不同 不同域名的跨域访问 什么是跨域? 简单地理解就是因 ...

  7. mysql数据库时间、字符串类型互转

    时间格式转换: select DATE_FORMAT(NOW(),"%y-%m-%d %H:%i:%s") 字符串转时间: select STR_TO_DATE("201 ...

  8. MyBatis自动获取主键,MyBatis使用Oracle返回主键,Oracle获取主键

    MyBatis自动获取主键,MyBatis使用Oracle返回主键,Oracle获取主键 >>>>>>>>>>>>>> ...

  9. 常见的IE6兼容以及css兼容

    IE6虽然随着XP系统退出市场在国外基本基本消失,但是在国内依然占据很大的市场份额.政务网站.页游官网等依然要考虑到IE6用户的体验.如果你的网站使用CSS3等“新技术”时,就必须果断放弃IE6的兼容 ...

  10. union的用法

    union的用法 union用来连接两个查询语句,把两个查询语句的查询结果合并起来,两个查询语句的查询字段个数必须一样,否则会出错,查询的字段可以不一样,类型也可以不一样,但是这样查询的意义不大,如果 ...