#ifndef#define与namespace杂谈

一、#ifndef#define#endif

注意问题:变量一般不要定义在.h文件中。

总结:

二、#define宏定义

三、namespace命名空间


一、#ifndef#define#endif

首先说明下几点基础知识:

  1.预编译阶段把所有#include ”***.h“ (“”与<>的区别这里就不说了)用***.h的内容来替换了, 所以之后就没有.h了所有.h的内容都已经包含进了需要它们的.cpp中。

  2.生成最后的exe文件是由编译、链接两步完成的, 编译是源代码生成obj二进制目标文件的过程, 注意一个源代码文件(指.cpp, 而非.h, .h已经被包含进.cpp中了)生成一个obj文件。
详情可参见:https://blog.csdn.net/qq_30815237/article/details/88948632

从语法上来分析下#ifndef#define#endif

头文件“a.h”如下:

//-----a.h-----
#ifndef A_H_
#define A_H_
void hello();
#endif

     在预编译阶段, 当第一次执行该段代码(即#include "a.h",参见第一条)时, 由于我们并没有宏定义A_H_, 所以会执行#define A_H_以及void fun()两条语句, 第二次执行该段代码时因为#ifndef A_H_为假就直接走到#endif后面也就等于该次#include "a.h"什么也没做了     因此头文件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件a.h。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,出现大量的声明冲突。 
      所以把头文件的内容都放在#ifndef和#endif中。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的: 

#ifndef <标识> 
#define <标识> 


...... 
...... 

#endif 

<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:a.h 

#ifndef A_H_ 
#define A_H_ 
...... 

#endif 

注意问题:变量一般不要定义在.h文件中。

总结:

      当我们一个简单的project中有三个文件main.cpp, a.cpp, a.h,而 main.cpp 和a.cpp分别包含了a.h, 在预编译阶段, 两个编译单元是都会分别包含a.h的, 即使他们使用了#ifndef#define#endif, 这也是为什么当a.h被多个文件包含时我们不允许在a.h中定义变量及函数的原因, 因为在链接阶段会出现重定义。 但是在a.h中定义一个static变量却是允许的, 因为static变量是模块性作用域, 就这个例子来说, 若我们在a.h中写static int sss = 0;那么main.cpp与a.cpp使用的sss将为2个独立的sss.

        那么是否#ifndef#define#endif就没用了呢, 大家可以想想, 当我们a.cpp中写了多个#include "a.h"时, 如果我们使用了#ifndef#define#endif,那么预编译阶段就只会包含一个a.h中的内容到a.cpp中, 你也许会说, 有谁会傻到在a.cpp中写多个#include "a.h"呢, 那么请考虑稍微复杂点的情况, 当我们main.cpp中包含了a.h和b.h, 而a.h中我们又包含了b.h, 那么如果我们使用了#ifndef#define#endif则main.obj只会包含一份b.h。

from:https://blog.csdn.net/q191201771/article/details/6399820

from:https://blog.csdn.net/mad1989/article/details/7920173?utm_source=blogxgwz9


二、#define宏定义

        为了程序的通用性,可以使用#define预处理宏定义命令,它的具体作用,就是方便程序段的定义和修改。举个例子,如果一个项目的代码很长,有5000多行,而且基本上裏面的同一个常量N就占了3000多行,如果说今后你要是想对这个常量N的值进行修改,如果在程序的开始没有定义一个#define N,那么改起来不是很麻烦,那不是要晕过去了,如果你事先定义了一个      #  define N ‘常量值’,那么当你要修改程序内部的常量值时,只要修改N后面的常量值就等于把程序内部的要修改的相同常量值都改了。

   define将一个变量强制定义为你想要的值。如#define N 3.14就是将PI的值定义成3.14,这样在程序里看到N就可以替换成3.14

简单的define定义

#define MAXTIME 1000

一个简单的MAXTIME就定义好了,它代表1000,如果在程序里面写:

if(i<MAXTIME){.........}

编译器在处理这个代码之前会对MAXTIME进行处理替换为1000。

这样的定义看起来类似于普通的常量定义CONST,但也有着不同,因为define的定义更像是简单的文本替换,而不是作为一个量来使用,这个问题在下面反映的尤为突出:

宏定义的缺点: 

(1) 无法对宏定义中的变量进行类型检查 

此缺点,是相对于const变量来说的:

二者的区别:
(1) #define是在编译的预处理阶段起作用,而const是在编译、运行的时候起作用。
(2)方式: #define只是简单的字符串替换,没有类型检查。而const有对应的数据类型,是要进行判断的,可以避免一些低级的错误。 
(3)存储:#define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若干个备份???;const定义的只读变量在程序运行过程中只有一份备份。
(4)调试: const常量可以进行调试的,define是不能进行调试的,因为在预编译阶段就已经替换掉了。

const优点:
(1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
(2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
(3)const可节省空间,避免不必要的内存分配,提高效率

        define仅仅是编译时期替换,所以其定义的变量,是不会在运行时候分配内存的,不占用内存空间. const定义的变量,是 Run-Time时期的变量,如果类型不匹配,系统在运行时候,就会发现并提示或报错,对应的,const变量在运行时期,也是一种变量,系统会为其分配内存. ???

#define PI 3.14     //预处理后 占用代码段空间
const float PI=3.14;    //本质上还是一个 float,占用数据段空间

(2) 边界效应 

A. 未加括号带来的边界效应 
由于宏定义的时候,其各个分量未加括号,而在使用宏定义的时候,传递的参数是变量的表达式,然后经过系统展开后,由于优先级的原因,导致其结果不是你所希望的. 例如:

#define MUL(A,B) A*B

而在使用的时候,这样的调用: 
int a=1,b=2,c=3,d=0; 
d=MUL(a+b,c) 
经过编译时候展开,就变成了 
d=a+b*c 
而不是我们所希望的 
d=(a+b)*c 
[解决办法] 
其解决办法也很简单,就是给每个分量,都加上括号,就可以避免此类问题 
即,在宏定义的时候,如此定义:

#define MUL(A,B) ((A)*(B))

from:https://blog.csdn.net/xianqianshi3004/article/details/79278170

from:https://blog.csdn.net/yi_ming_he/article/details/70405364


三、namespace命名空间

      namespace是C++新加的一个概念,中文名为命名空间,相对来说更便捷地解决了函数重名和变量命名的问题。其一般定义如下形式:

                  namespace 命名空间名{变量声明或函数声明}。

       一般使用命名空间中的变量或函数则通过"命名空间名::变量或函数"来使用,如下面代码所示。可能有人会问命名空间存在的意义在哪,自己写的程序完全可以规避命名相同的情况,不过假如你调用其他人所写的程序则有很大的可能有变量重名以及函数重名的问题,然而命名空间的撞车概率则相对较小,显然。

      再看下面代码中的程序第二行为"using namespace std;",这个using又是做什么的。我们知道#include<iostream>是引入iostream文件中的代码,其中定义了std命名空间,而cout,endl则声明在std命名空间内,假如不使用using关键字,cout和endl则需要写成std::cout以及std::endl,而cout以及endl都是我们需要经常使用的,这就增加了大量的代码量,通过using则可以在主函数中直接调用命名空间中的变量和函数。当命名空间之间变量命名有冲突也能使用using关键字,但是在使用变量的时候仍需在前面加上命名空间以示区别,如代码最后两行。

#include <iostream>
using namespace std;

namespace A
{
  int x=0;
  void function(){};            
}

namespace B
{
  int x=1;
  void function(){};
}
using namespace A;
using namespace B;
int main(){
  cout << A::x << endl;
  cout << B::x << endl;
  return 0;
}

from:https://www.cnblogs.com/lun14061076/p/6514172.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值