防止变量重复定义、头文件重复包含、嵌套包含
- 格式:doc
- 大小:40.50 KB
- 文档页数:15
C语言的头文件常用于声明函数、变量、宏和结构体等的定义,以便在多个源文件中共享和重用这些声明。
以下是C语言头文件的一般写法:
c
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// 在这里写下头文件的内容
#endif /* HEADER_NAME_H */
头文件的命名通常使用全大写字母,可以根据需要选择有意义的名称。
头文件中应该包含以下内容:
防止多重包含:使用条件编译指令#ifndef、#define 和#endif,以避免头文件被重复包含。
函数声明:声明函数的原型,例如int add(int a, int b);。
变量声明:声明变量的外部链接性,例如extern int globalVariable;。
宏定义:定义常量、宏函数和条件编译宏等,例如#define PI 3.14159。
结构体定义:定义结构体类型,例如struct Person { char name[20]; int age; };。
请注意以下几点:
头文件中通常只包含声明,而不包含具体的实现代码。
实现代码应该在对应的源文件中编写。
头文件应该包含所需的其他头文件,以确保所有依赖关系得到满足。
在编写头文件时,应使用预处理指令#ifdef 和#ifndef 来避免重复定义和冲突。
头文件应该尽量精简和模块化,只包含与该头文件相关的声明。
在头文件中避免定义全局变量,因为头文件可能会被多个源文件包含,这样会导致变量的重复定义。
正确编写和组织头文件可以提高代码的可读性、可维护性和重用性,推荐遵循良好的编码规范和项目约定。
C语言中的三种预处理功能C语言中的三种预处理功能导语:预处理指令是以#号开头的代码行。
#号必须是该行除了任何空白字符外的第一个字符。
#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。
整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
下面是C语言三种预处理功能,欢迎阅读:指令用途# 空指令,无任何效果#include 包含一个源代码文件#define 定义宏#undef 取消已定义的宏#if 如果给定条件为真,则编译下面代码#ifdef 如果宏已经定义,则编译下面代码#ifndef 如果宏没有定义,则编译下面代码#elif 如果前#if条件不为真,当前条件为真,则编译下面代码,其实就是else if的简写#endif 结束一个#if……#else条件编译块#error 停止编译并显示错误信息特殊符号预编译程序可以识别一些特殊的符号。
预编译程序对于在源程序中出现的这些串将用合适的值进行替换。
注意,是双下划线,而不是单下划线。
FILE 包含当前程序文件名的字符串LINE 表示当前行号的整数DATE 包含当前日期的字符串STDC 如果编译器遵循ANSI C标准,它就是个非零值TIME 包含当前时间的字符串//例#includeint main(){printf("Hello World! ");printf("%s ",__FILE__);printf("%d ",__LINE__);return 0;}1. 宏定义不带参数宏定义又称为宏代换、宏替换,简称“宏”。
预处理(预编译)工作也叫做宏展开:将宏名替换为字符串,即在对相关命令或语句的含义和功能作具体分析之前就要换。
格式:#define 标识符字符串其中标识符就是所谓的符号常量,也称为“宏名”。
例:#define Pi 3.1415926//把程序中出现的Pi全部换成3.1415926 说明:(1)宏名一般用大写;(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。
c++define用法c++中define用法define在c++语言中用法比较多,这里对其进行整理。
1.无参宏定义无参宏的宏名后不带参数。
其定义的一般形式为:#define 标识符字符串其中的“#”表示这是一条预处理命令。
凡是以“#”开头的均为预处理命令。
“define”为宏定义命令。
“标识符”为所定义的宏名。
“字符串”可以是常数、表达式、格式串等。
例如:#define MAXNUM 99999这样MAXNUM就被简单的定义为99999。
2.有参宏定义C++语言允许宏带有参数。
在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。
对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
带参宏定义的一般形式为:#define 宏名(形参表) 字符串在字符串中含有各个形参。
在使用时调用带参宏调用的一般形式为:宏名(实参表);例如:#define add(x, y) (x + y)int main(){cout << "1 plus 1 is " << add(1, 1.5) << ".\n";system("pause");return(0);}这个“函数”定义了加法,但是该“函数”没有类型检查,有点类似模板,但没有模板安全,可以看做一个简单的模板。
注意:该“函数”定义为(a + b),在这里加括号的原因是,宏定义只是在预处理阶段做了简单的替换,如果单纯的替换为a + b时,当你使用5 * add(2, 3)时,被替换为5 * 2 + 3,值为13,而非5 * (2 + 3),值为25。
3.宏定义中的特殊操作符define 中的特殊操作符有#,##和… and __VA_ARGS__ (1)#假如希望在字符串中包含宏参数,ANSI C允许这样作,在类函数宏的替换部分,#符号用作一个预处理运算符,它可以把语言符号转化程字符串。
软件编程标准总结本标准的内容包括:基本原则、布局、注释、命名规则、变量常量与类型、表达式与语句、函数与过程、可靠性、可测性、断言与错误处理等。
一、基本原则1.保持代码的简明清晰,防止过分的编程技巧。
2.所有的代码尽量遵循ANSI C标准。
3.编程时首先到达正确性,其次考虑效率。
4.防止或少用全局变量。
5.尽量防止使用GOTO语句。
6.尽可能重用、修正老的代码。
7.尽量减少同样的错误出现的次数。
二、文件布局1.头文件必须要防止重复包含。
2.包含标准库头文件用尖括号 < >,包含非标准库头文件用双引号“”。
3.遵循统一的顺序书写类的定义及实现。
类的定义〔在定义文件中〕按如下顺序书写:公有属性公有函数保护属性保护函数私有属性私有函数类的实现〔在实现文件中〕按如下顺序书写:构造函数析构函数公有函数保护函数私有函数4.程序中一行的代码和注释不能超过80列。
5.定义指针类型的变量,*应放在变量前。
6.源程序中关系较为紧密的代码应尽可能相邻。
iLength = 10;iWidth = 5; // 矩形的长与宽关系较密切,放在一起。
StrCaption = “Test”;7.禁止使用TAB键,必须使用空格进行缩进。
缩进为4个空格。
8.程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。
{ }之内的代码块使用缩进规则对齐。
9.if、else、else if、for、while、do等语句自占一行,执行语句不得紧跟其后。
不管执行语句有多少都要加 { }。
if (varible1 < varible2){varible1 = varible2;}10.11.声明类的时候,public、protected、private关键字与分界符{} 对齐,这些部分的内容要进行缩进。
12.结构型的数组、多维的数组如果在定义时初始化,按照数组的矩阵结构分行书写。
13.相关的赋值语句等号对齐。
c语言头文件互引用
C语言头文件互引用是指两个或多个头文件相互包含的情况。
在C语言中,头文件是扩展名为.h的文件,包含了C函数声明和宏定义,被多个源文件中引用共享。
一、头文件互引用会导致以下问题:
1.编译错误:如果两个头文件互相包含,会导致编译器无法确定哪个头文件应该先被包含,从而导致编译错误。
2.重复定义:如果两个头文件都定义了相同的宏或函数,会导致重复定义错误。
3.代码膨胀:头文件互引用会导致代码膨胀,降低代码可读性和可维护性。
二、为了避免头文件互引用问题,可以采取以下措施:
1.使用ifndef/endif宏:使用ifndef/endif宏可以防止重复定义。
2.使用pragma once:使用pragma once可以防止头文件被重复包含。
3.合理组织头文件:将相关的头文件组织在一起,可以减少头文件之间的依赖关系。
防止头文件被重复包含的方法
防止头文件被重复包含是在C++编程中非常重要的问题。
重复包含头文件可能会导致编译错误或者意外的行为。
以下是一些常见的方法来防止头文件被重复包含:
1. 使用预处理器指令:可以使用条件编译指令来确保头文件只被包含一次。
例如,可以在头文件的开头加上以下代码:
c++。
#ifndef MY_HEADER_FILE_H.
#define MY_HEADER_FILE_H.
// 头文件内容。
#endif.
这样,如果这个头文件已经被包含过了,预处理器会跳过其中的内容,从而避免重复包含。
2. 使用#pragma once指令,一些编译器支持#pragma once指令,这是另一种防止头文件被重复包含的方法。
在头文件的开头加
上#pragma once即可确保它只被包含一次。
3. 使用include guards,这是一种类似于第一种方法的技术,通过在头文件的开头和结尾加上特定的宏定义来防止重复包含。
4. 使用前置声明,在一些情况下,可以使用前置声明来代替包
含头文件,从而避免重复包含的问题。
前置声明是在不需要知道对
象的完整定义的情况下声明它的存在,比如类的声明。
总的来说,以上这些方法都可以有效地防止头文件被重复包含,程序员可以根据实际情况选择合适的方法来确保代码的健壮性和可
维护性。
如何在C语言中自己写头文件一些初学C语言的人,不知道头文件(*.h文件)原来还可以自己写的。
只知道调用系统库函数时,要使用#includ e语句将某些头文件包含进去。
其实,头文件跟.C文件一样,是可以自己写的。
头文件是一种文本文件,使用文本编辑器将代码编写好之后,以扩展名.h保存就行了。
头文件中一般放一些重复使用的代码,例如函数声明,变量声明,常数定义,宏的定义等等。
当使用#includ e语句将头文件引用时,相当于将头文件中所有内容,复制到#includ e处。
为了避免因为重复引用而导致的编译错误,头文件常具有#ifndef LABEL#define LABEL//代码部分#endif的格式。
其中,LABEL为一个唯一的标号,命名规则跟变量的命名规则一样。
常根据它所在的头文件名来命名,例如,如果头文件的文件名叫做hardw are.h,那么可以这样使用:#ifndef __HARD WARE_H__#define __HARD WARE_H__//代码部分#endif这样写的意思就是,如果没有定义__HAR DWARE_H__,则定义__H ARDWA RE_H__,并编译下面的代码部分,直到遇到#endif。
这样,当重复引用时,由于__HA RDWAR E_H__已经被定义,则下面的代码部分就不会被编译了,这样就避免了重复定义。
另外一个地方就是使用i nclud e时,使用引号与尖括号的意思是不一样的。
使用引号(“”)时,首先搜索工程文件所在目录,然后再搜索编译器头文件所在目录。
而使用尖括号(<>)时,刚好是相反的搜索顺序。
假设我们有两个文件名一样的头文件hardw are.h,但内容却是不一样的。
在编程中如何避免变量与常量的重复定义在编程中,变量和常量是我们经常使用的概念。
它们都是用来存储数据的,但在使用过程中需要注意避免重复定义的问题。
本文将探讨在编程中如何避免变量与常量的重复定义的方法。
1. 命名规范在编程中,良好的命名规范是避免变量与常量重复定义的基础。
我们应该为变量和常量选择具有描述性的名称,以便于理解和区分。
例如,可以使用有意义的变量名来表示不同的数据,而不是使用类似的名称来定义多个变量。
2. 作用域作用域是指变量或常量在程序中可见和可访问的范围。
在避免重复定义的问题上,正确使用作用域是至关重要的。
我们应该将变量和常量定义在合适的作用域内,以避免与其他同名的变量或常量发生冲突。
3. 局部变量和全局变量在编程中,局部变量和全局变量是两种常见的变量类型。
局部变量定义在函数或代码块内部,只在其所在的作用域中可见。
而全局变量定义在函数或代码块之外,可以在整个程序中被访问。
为了避免变量与常量的重复定义,我们可以将变量定义为局部变量或全局变量,根据具体的需求选择合适的范围。
4. 常量定义在编程中,常量是指在程序执行过程中不可更改的值。
为了避免常量的重复定义,我们可以使用常量定义语句将常量集中在一起,并在需要使用的地方引用。
这样可以方便地修改和管理常量的值,避免多次定义相同的常量。
5. 使用注释注释是编程中常用的工具,可以提供代码的解释和说明。
在避免变量与常量重复定义的过程中,我们可以使用注释来标记已经定义的变量或常量,以提醒其他开发人员避免重复定义。
这样可以增加代码的可读性和可维护性。
总结起来,避免变量与常量的重复定义需要遵循良好的命名规范,正确使用作用域,合理选择变量的类型和范围。
通过集中定义常量并使用注释来提醒其他开发人员,可以有效地避免变量与常量的重复定义问题。
在编程中,我们应该注重代码的可读性和可维护性,避免出现不必要的冲突和错误。
LINK2005错误——重复定义错误编程中经常能遇到LNK2005错误——重复定义错误,其实LNK2005错误并不是一个很难解决的错误。
弄清楚它形成的原因,就可以轻松解决它了。
造成LNK2005错误主要有以下几种情况:1.重复定义全局变量。
可能存在两种情况:A、对于一些初学编程的程序员,有时候会以为需要使用全局变量的地方就可以使用定义申明一下。
其实这是错误的,全局变量是针对整个工程的。
正确的应该是在一个CPP文件中定义如下:int g_Test;那么在使用的CPP文件中就应该使用:extern int g_Test即可,如果还是使用int g_Test,那么就会产生LNK2005错误,一般错误错误信息类似:AAA.obj error LNK2005 int book c?book@@3HA already defined in BBB.obj。
切记的就是不能给变量赋值否则还是会有LNK2005错误。
这里需要的是“声明”,不是“定义”!根据C++标准的规定,一个变量是声明,必须同时满足两个条件,否则就是定义:(1)声明必须使用extern关键字;(2)不能给变量赋初值所以,下面的是声明:extern int a;下面的是定义int a; int a = 0; extern int a =0;B、对于那么编程不是那么严谨的程序员,总是在需要使用变量的文件中随意定义一个全局变量,并且对于变量名也不予考虑,这也往往容易造成变量名重复,而造成LNK2005错误。
2.头文件的包含重复。
往往需要包含的头文件中含有变量、函数、类的定义,在其它使用的地方又不得不多次包含之,如果头文件中没有相关的宏等防止重复链接的措施,那么就会产生LNK2005错误。
解决办法是在需要包含的头文件中做类似的处理:#ifndef MY_H_FILE //如果没有定义这个宏#define MY_H_FILE //定义这个宏……. //头文件主体内容…….#endif上面是使用宏来做的,也可以使用预编译来做,在头文件中加入:#pragma once//头文件主体3.使用第三方的库造成的。
【转载】防止变量重复定义、头文件重复包含、嵌套包含【转自】 /zengzhaonong/blog/item/8a8871062d481f7f03 088106.html#include文件的一个不利之处在于一个头文件可能会被多次包含,为了说明这种错误,考虑下面的代码:#include "x.h"#include "x.h"显然,这里文件x.h被包含了两次,没有人会故意编写这样的代码。
但是下面的代码:#include "a.h"#include "b.h"看上去没什么问题。
如果a.h和b.h都包含了一个头文件x.h。
那么x.h在此也同样被包含了两次,只不过它的形式不是那么明显而已。
多重包含在绝大多数情况下出现在大型程序中,它往往需要使用很多头文件,因此要发现重复包含并不容易。
要解决这个问题,我们可以使用条件编译。
如果所有的头文件都像下面这样编写:#ifndef _HEADERNAME_H#define _HEADERNAME_H...//(头文件内容)#endif那么多重包含的危险就被消除了。
当头文件第一次被包含时,它被正常处理,符号_HEADERNAME_H被定义为1。
如果头文件被再次包含,通过条件编译,它的内容被忽略。
符号_HEADERNAME_H按照被包含头文件的文件名进行取名,以避免由于其他头文件使用相同的符号而引起的冲突。
但是,你必须记住预处理器仍将整个头文件读入,即使这个头文件所有内容将被忽略。
由于这种处理将托慢编译速度,所以如果可能,应该避免出现多重包含。
test-1.0使用#ifndef只是防止了头文件被重复包含(其实本例中只有一个头件,不会存在重复包含的问题),但是无法防止变量被重复定义。
# vi test.c-------------------------------#include <stdio.h>#include "test.h"extern i;extern void test1();extern void test2();int main(){test1();printf("ok\n");test2();printf("%d\n",i);return 0;}# vi test.h-------------------------------#ifndef _TEST_H_#define _TEST_H_char add1[] = "\n"; char add2[] = "\n"; int i = 10;void test1();void test2();#endif# vi test1.c-------------------------------#include <stdio.h>#include "test.h"extern char add1[];void test1(){printf(add1);}# vi test2.c-------------------------------#include <stdio.h>#include "test.h"extern char add2[]; extern i;void test2(){printf(add2);for (; i > 0; i--)printf("%d-", i);}# Makefile-------------------------------test: test.o test1.o test2.otest1.o: test1.ctest2.o: test2.cclean:rm test test.o test1.o test2.o错误:test-1.0编译后会出现"multiple definition of"错误。
错误分析:由于工程中的每个.c文件都是独立的解释的,即使头文件有#ifndef _TEST_H_#define _TEST_H_....#enfif在其他文件中只要包含了global.h就会独立的解释,然后每个.c文件生成独立的标示符。
在编译器链接时,就会将工程中所有的符号整合在一起,由于文件中有重名变量,于是就出现了重复定义的错误。
解决方法在.c文件中声明变量,然后建一个头文件(.h文件)在所有的变量声明前加上extern,注意这里不要对变量进行的初始化。
然后在其他需要使用全局变量的.c文件中包含.h文件。
编译器会为.c生成目标文件,然后链接时,如果该.c文件使用了全局变量,链接器就会链接到此.c文件。
test-2.0# vi test.c-------------------------------#include <stdio.h>#include "test.h"int i = 10;char add1[] = "\n";char add2[] = "\n";extern void test1(); extern void test2();int main(){test1();printf("ok\n");test2();printf("%d\n",i); return 0;}# vi test.h-------------------------------#ifndef _TEST_H_#define _TEST_H_extern i;extern char add1[]; extern char add2[];void test1();void test2();#endif# vi test1.c-------------------------------#include <stdio.h>#include "test.h"void test1(){printf(add1);}# vi test2.c-------------------------------#include <stdio.h>#include "test.h"void test2(){printf(add2);for (; i > 0; i--)printf("%d-", i);}二、链接指示符:extern如果希望调用其他程序设计语言(尤其是C)写的函数,那么,调用函数时必须告诉编译器使用不同的要求.例如,当这样的函数被调用时,函数名或参数排列的顺序可能不同,无论是C++函数调用它,还是用其他语言写的函数调用它.程序员用链接指示符(linkage directive)告诉编译器,该函数是用其他的程序设计语言编写的.链接指示符有两种形式:单一语句(single statement)形式复合语句(compound statement)形式当复合语句链接指示符的括号中包含有#include时,在头文件中的函数声明都被假定是用链接指示符的程序设计语言所写的.链接指示符不能出现在函数体中.vi externC.cpp-------------------------------------#include <iostream>extern "C" double sqrt(double);int main(){using std::cout;using std::endl;double result = sqrt(25);cout << "result = " << result << endl;return 0;}g++ externC.cpp如果我们希望C++函数能够为C程序所用,我们也可以使用extern "C"链接指示符来使C++函数为C程序可用.作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。
函数被C++编译后在symbol库中的名字与C语言的不同。
例如,假设某个函数的原型为:void foo(int x, int y);该函数被C编译器编译后在symbol库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。
_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
为了实现C和C++的混合编程,C++提供了C链接交换指定符号extern "C"来解决名字匹配问题,函数声明前加上extern "C"后,则编译器就会按照C语言的方式将该函数编译为_foo,这样C语言中就可以调用C++的函数了。
cppExample.h-----------------------------------#ifndef CPP_EXAMPLE_H#define CPP_EXAMPLE_H//被extern "C"限定的函数或变量首先是extern类型的;extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
//被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;extern "C" int add(int x, int y);//extern int add(int x, int y);#endifcppExample.cpp-----------------------------------#include "cppExample.h"int add( int x, int y ){return x + y;}cFile.c-----------------------------------#include <stdio.h>//这样会编译出错//#include "cppExample.h"extern int add(int x, int y);int main(int argc, char* argv[]){printf("%d\n", add(2, 3));return 0;}-----------------------------------gcc cFile.c cppExample.cpp三、变量定义与声明的区别我们在程序设计中,时时刻刻都用到变量的定义和变量的声明,可有些时候我们对这个概念不是很清楚,知道它是怎么用,但却不知是怎么一会事,下面我就简单的把他们的区别介绍如下:变量的声明有两种情况:(1) 一种是需要建立存储空间的(定义、声明)。