html引用c 变量,Y.A.K.E

记录一次C++项目改造中定义全局变量的操作.

我对C/c++不太熟悉,在修改别人项目的时候,想弄个文件,专门存放全局变量.

然后各种不对.

xxx previously defined here错误 或者 error: redefinition of xxx或者initialized and declared 'extern'

反正各种问题.

其实根本原因就是重复引用导致的.

include引用

include 包含一个.h文件,简单理解就是:

将.h文件的内容直接插入到当前位置.

如果

main.c 引入 a.h 和  b.h

而b.h 因为需要调用a.h一些变量,必须也要引用a.h

那么最后,合并的mian.c大致内容:

a.h内容 (main.c引入)

a.h内容(b.h引入)

b.h内容 (main.c引入)

main.c (除了include外的内容)

这样a.h的内容出现了两次.就会出现编译错误.

因为正常情况下,变量和函数都不能重复定义.

对于这种问题,解决比较简单.

宏条件语句

比如a.h文件大致内容:

#ifndef HEADER__A_H

#define HEADER__A_H

//代码

#endif

宏条件语句会在编译前进行预处理.

如果没有定义"HEADER__A_H"的时候,

定义下"HEADER__A_H",并插入代码.

如果"HEADER__A_H"已经定义,将不满足宏条件, 所以#ifndef  到 #endif内容全部会忽略.

所以,只会在第一次引入的时候满足宏条件.

再回到上面的main.c 预处理后 :

a.h内容 (main.c引入,并定义了"HEADER__A_H")

a.h内容(b.h引入,内容是空的.)

b.h内容 (main.c引入)

main.c (除了include外的内容)

因为第一次引入a.h的时候,定义了"HEADER__A_H"宏,所以,之后再调用.a.h都不会触发宏条件语句为"true"的情况.

所以只有第一次引入a.h的时候,会插入a.h内容.

之后再引用a.h的时候因为宏条件语句无法满足,所以后面插入的内容是空的.

即使这样还是会出现变量,或者函数重复定义的情况.然后我再补充下C/c++项目编译过程.

编译过程

一个项目多有多个.c/.cpp文件.

编译过程是

gcc 分别编译每个.c/.cpp文件.编译成.o文件

然后

ld 链接这些.o文件.编译成最终可执行文件.

重点是分别两个字.

假设

main.c 引入 a.h

m2.c 也引入a.h

因为main.c和m2.c两个文件时分别编译的.

所以编译出来的

main.o 和m2.o 两个文件都会完整的引入并一起编译a.h内容.

ld链接这些.o文件的时候,.就有相同的标签(汇编的全局标签),导致链接失败.

C语言当初设计了一个关键词专门来解决这种问题.

extern

extern 后面跟着函数原型,或者变量定义.

例子

extern int abc;

extern void test(int code);

作用就是骗编译器.告诉编译器,这个变量,或者函数在其他地方已经定义了.

让编译器不再重新定义.这样避免最后ld链接的时候,找到相同的标签导致链接失败.

extern 的变量和函数可以多次声明.但是一定要有一个原始声明.

extern 是"假声明",你必须要有个"真声明".才能ld链接成功.

搞懂这些,就搞懂了为啥会重复引用了.

推荐操作

也就是项目全局变量定义的方法,规避重复引用的办法.

config.c

我们将全局变量声明放这里.这里是"真声明" .

// config.c

//引入它同名的头文件

#include "config.h"

//定义变量,并给初始值

int abc=123;

//仅定义变量,不给初始值.

bool test;

//定义函数

int mAdd(int a,int b) {

return a+b;

}

config.h

config.h文件然后将c声明的变量复制一份.然后分别加上extern标识符即可.

切记. extern后跟着的变量不要用等号进行赋值.

#ifndef CONFIG_H

#define CONFIG_H

// config.h

//严禁对变量初始化

// 错误 → extern int abc=123;

//正确 ↓

extern int abc;

extern bool test;

//类似函数原型.

extern int mAdd(int a, int b);

#endif // CONFIG_H

其他.c/.cpp/.h文件只要大胆的引用config.h 注意是H文件.即可完美的处理.

分析

举例5个文件

main.c   主函数

m2.c   自写的逻辑算法库

m2.h   逻辑算法库函数的声明(函数原型)

config.c  全局变量声明

config.h   给每个全局变量加上extern关键词

main.c 引用 m2.h 和config.h   ,其中m2.h中也引入了config.h

m2.c 引用了 m2.h 和config.h

config.c 引用了 config.h

编译流程

实际上就是gcc编译三个.c文件.然后将编译出来三个.文件链接成可执行文件.

推导

假设,先gcc编译main.c

那么预处理后

config.h内容 (main.c引入)

config.h内容(由m2.h引入,内容是空的.)

m2.h内容 (main.c引入)

main.c (除了include外的内容)

所以它能成功编译成main.o文件.

同理

gcc编译 m2.c

它的h没有互相引用,这个不用解释,只要没有语法错误,直接编译出m2.o文件

再同理可以推

gcc编译 config.c  也是直接编译成config.o文件

链接

重点是链接

main.o 引用的config.h用的extern ,没有分配标签.没有原始地址,但是链接器忽略错误,

m2.o 也引用了config.h,也是extern ,没有分配标签.没有原始地址,但是链接器忽略错误,

然后是config.o 也引用了config.h 这里extern所以也是忽略的.重点是.config.c是原始分配了标签.有变量原始地址.

所以ld链接器让main.o 和m2.o(变量)标签在config.o找到了原始地址.

链接成功.编译出可执行文件.

总结

config.c 文件放变量

config.h 用宏条件指令防止重复包含. 然后对config.c变量做extern 额外声明.

其他的c或者h文件只需要#include "config.h" 就可以调用全局变量.

这样就不会出现重复定义,或者重复引用

遗留问题

extern 和 inline 关键词组合描述函数的时候,

正常库内,或者自己内部调用没问题.

在跨库的时候有问题.

参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/271552.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux python开发环境_如何在Linux系统中搭建Python编程环境

1 在大多数的Linux系统中,基本上都默认安装了Python,也就是说,在Linux的系统中基本上是不需要安装什么软件,就可以使用Python。 下面以ubuntu操作系统为例,看看如何在Linux操作系统中搭建Python编程环境。2 检查Ubuntu…

CentOS 搭建 LAMP服务器

CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙。 1、关闭firewall: systemctl stop firewalld.service #停止firewall systemctl disable firewalld.service #禁止firewall开机启动 2、安装iptables防火墙 yum install iptables-ser…

什么叫兜底条款

就是一个条款就能覆盖所有未说到的内容:如:"其它应当受到处罚的行为." 有了这样的条款,制度和法律才不会出现死角,让一些人钻空子,由于规定不可能十分周全,所心好多人还是在想方设法钻空子.

当你的电脑C盘满了怎么办?这两种方法都能解决

用了好几年的电脑,在分区的时候C盘空间分的太小;有的喜欢把下载的软件、工作时的文件都放在桌面上方便自己使用;有的安装软件的时候不选择安装目录或一些软件必须要安装在C盘,这样你的C盘的空间就会变得不够,今天分享下…

一个html有几个css,几个CSS的黑科技_html/css_WEB-ITnose

原文出处: JellyBool(JellyBool) 欢迎分享原创到伯乐头条昨天由于某些原因没有写博客,之前说好的每天一篇的,这篇是为了补昨天的了。然后我就要当一次标题党了。这里的黑科技其实就是一些CSS中不怎么为人所知但在解决某些问题的时候很溜的属性…

python递归函数讲解_带你深入学习Python——Python递归详解!

一、递归 递归:在调用一个函数的过程中,直接或间接地调用了函数本身这个就叫递归 注:Python在递归中没有像别的语言对递归进行优化,所以他的每一次调用都会基于上一次的调用进行,并且他设置了最大的递归数量防止递归外溢 递归调用…

51nod 1040最大公约数和(欧拉函数)

1040 最大公约数之和题目来源: rihkddd基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题收藏关注给出一个n,求1-n这n个数,同n的最大公约数的和。比如:n 61,2,3,4,5,6 同6的最大公…

计算机安全基础:加密技术知识笔记

1、加密技术介绍 加密技术是最常用的数据安全保密的手段,加密技术的关键在于加密/解密算法和密钥管理。 数据加密的过程:对明文文件或数据按照某种算法进行处理,变成密文。密文需要根据相应的密钥才能获得原来的明文信息,通过这种…

an导入html5,H5-FLASH:AN HTML5-BASED FLASH RUNTIME

摘要:Flash has been widely deployed to many internet applications.Nevertheless,as a closed development platform,there are more and more concerns arisen around its security and performance problems.On the other hand,HTML5 provides an alternative …

JAVA 获取格林威治时间(GMT)

记录下获取GMT时间的方法: //格式可根据需要自定义,如yyyy-MM-dd HH:mm:ss 等等 SimpleDateFormat sdf new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss GMT", Locale.US); Calendar calendar Calendar.getInstance(); sdf.setTimeZone(Tim…

Linux CentOS下安装Oracle

1 、在安装oracle之前首先安装以下组件包,直接输入下列语句安装。 yum install binutils* -y yum install compat-lib* -y yum install gcc* -y yum install glibc* -y yum install ksh* -y yum install libgcc* -y yum install libstdc* -y yum install libaio* -y…

计算机安全基础:认证技术知识笔记

1、认证技术介绍 认证技术主要是用来解决网络通信过程中通信双方身份的认可。认证的过程涉及加密和密钥交换。认证方一般都会有账户名、口令、使用摘要算法和基于PKI认证。 2、PKI系统介绍 PKI是一种遵循既定标准的密钥管理平台,能够为所有的网络应用提供加密和数字…

python 比例之差z假设检验_假设检验在数据分析中的应用

前言Z检验T检验独立样本t检验配对样本t检验单样本t检验前言在这篇文章中,我不会具体去推导检验统计量和相应拒绝域的得出,这对于大部分非统计学专业的人士来说是晦涩的,我只想通过一个案例告诉大部分初学者假设检验怎么在数据挖掘中使用。%ma…

中南民族大学计算机类有什么具体专业,中南民族大学计算机科学学院计算机科学与技术专业简介...

计算机科学与技术专业计算机科学与技术专业1985年开始招收本科生。1989年开设计算机应用专业。1998年教育部进行专业调整,成立了计算机科学与技术专业。2012年,计算机科学与技术专业获得校级品牌专业称号。计算机科学与技术专业师资雄厚,结构…

Java实现字母的大小写转换

String result1 "JAVA";String result2 "springcloud";/*** toLowerCase()* 大写转小写*/System.out.println(result1.toLowerCase());/*** 小写转大写* toUpperCase()*/System.out.println(result2.toUpperCase()); 运行截图如下:

iOS开发tableview二级联动的细节实现中注意的细节总结

首先说网络慢带来的数据显示问题 可以通过判断请求参数是否一致来刷新tableview。 SJBCategaryModel * categaryModel self.categarys[CategarySelectRow]; NSMutableDictionary * params [NSMutableDictionary dictionary]; categaryModel.currentPage 1; params["a&q…

linux ctrlc 退出循环_linux按行读取 (while read line与forloop)

在linux下一般用while read line与for循环按行读取文件。这两种方法有什么区别呢&#xff1f;现有如下test.txt文件&#xff1a;1while read linewhile read line; do echo $linedone < test.txt输出结果与上图一致。这里也可以写为&#xff1a;cat test.txt | while read …

计算机系统基础:计算机可靠性知识笔记

1、计算机可靠性介绍 计算机的硬件故障通常都是由于元器件失效造成的。元器件的可靠性分为三个阶段&#xff1a;开始阶段元器件处于不稳定阶段失效率比较高、第二阶段是正常工作阶段&#xff0c;失效率最低、第三阶段元器件开始老化&#xff0c;失效率就又开始提高。又称为“浴…

python时间计算_python datetime库使用和时间加减计算

datetime库使用 一、操作当前时间 1.获取当前时间 >>> importdatetime>>> printdatetime.datetime.now()2019-07-11 14:24:01.954000 时间格式化输出&#xff1a; >>> print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")2019-…

桌面计算机打开不了怎么办,电脑桌面上的所有东西都打不开了 怎么处理

1、如果各分区下带autorun.inf一类的隐藏文件&#xff0c;删除后最好重新启动电脑。2、在文件类型中重新设置打开方式(以XP为例)打开 我的电脑&#xff0d;&#xff0d;工具&#xff0d;&#xff0d;文件夹选项&#xff0d;&#xff0d;文件类型&#xff0c;找到“驱动器”或“…