One Definition Rule
转换单元
我们写好的.cpp 和 .c 文件都会#include 引入头文件 合并后,称为一个 转换单元\翻译单元\编译单元
编译器单独的将每一个转换单元生成对应的对象文件(.obj);
对象文件包含了转换单元的机器码和转换单元的引用信息(不在转换单元中定义的对象);
最后链接器将各个转换单元的对象文件链接起来生成我们的目标程序;
比如在对象文件a中包含了定义在其他转换单元的引用那么就去其他转换单元的对象文件中寻找这个引用的定义来建立链接如果所有的对象文件中都找不到这个定义那么就会生成一个链接错误
未定义行为
记我们在编写代码中C标准未作规定的行为称为未定义行为,未定义行为的结果是不确定的。
具体在不同的编译器下会有不同的效果
比如:c=2*a++ + ++a*6;
这里 先算 a++ 还是++a 就是一个未定义行为;
比如:int x=-25602; x=x>>2;
x的结果在不同的编译器下是不确定的,因为这也属于未定义行为
ODR(One Definition Rule) 单一定义规则
ODR是一系列规则而不是一个规则程序中定义的每个对象对应着自己的规则。
但是基本上来讲任何的变量,函数,类,枚举,模板,概念(c++20)在每个转换单元中都只允许有一个定义;非inline的函数或者变量(c++17),在整个程序中,有且只有一个定义;
名称的链接属性
程序中的变量,函数,结构等都有着自己的名字,这些名字都有不同的链接属性,链接器就是根据这些链接属性来把各个对象文件链接起来的;
链接属性分为一下三种:
内部链接属性:该名称仅仅在本转换单元中有效 const static
外部链接属性:该名称在其他的转换单元中也有效 extern
无连接属性:该名称仅仅能够用于该名称的作用域内访问
#define
#define A B
//将标识符 A 定义为 B
#define 整数 int
整数 a = 250;
#define ita int a
ita {250};
#deifne x
#ifndef x
//....
#endif //! x
#define X //会让变量a删除
int x a{2500};
#define _in_
int ave(_in_ int a,_out_ int b){
return a+b;
}
#undef x 取消定义
定义复杂表达式的宏
#define SUM(X,Y) X+Y
#define AVE(X,Y) (X+Y)/2
#define RELEASE(X) delete[] x;x=nullptr;
定义复杂表达式宏
" # " 可以将一个标识符参数字符串化
#define SHOW(X) std::cout<<#X //(#传入的X可以处理成字符串)
SHOW(1234fg);=>std::cout<<"12345fg"
##可以连接两个标识符
#define T1(X,Y) void X##Y() {std::cout<<#Y;}
tt22();
namespace
namespace t{
int x{1};
}
t::x = 100;
using namespace t;
//就可直接适用
全局命名空间
int a;
::a = 255;
main(){
int a = 233;
cout<<::a; //通过全局命名空间就可以访问到外面的 变量
}
所有具有链接属性的对象,只要没有定义命名空间,就默认定义在全局命名空间中
命名空间的扩展
namespace a{
int c{888};
}
//a1.h
namespace a{
int v{888};
}
命名空间的声明及定义
namespace t{
extern int value;
void test();
}
int t::value = 10;
void t::test(){
//实现;
}
命名空间的嵌套
namespace s1{
namespace s2{
void test();
}
}
void s1::s2::test(){
}
未命名的命名空间
不给命名空间指定名称
namespace{
void hack(){
//在本转换单元中 不影响使用
}
}
预处理指令逻辑
#ifdef
防止头文件多次嵌套
#ifndef _NAME_ //如果没有定义 _NAME_
#define _NAME_
#else
//如果定义过则执行这...
#endif //结束
其他用法
#define VERSION 100
#define ENABLE 1
#if (VERSION==100)&& ENABLE
void sendMessage(100);
#elif VERSION==120
void sendMessage(120);
#else
void sendMessage(0000);
#enif
预定义宏
标准预定义标识符
_ _func_ _ (函数名称)
//编译器支持ISO C99 和 ISO C++11 指定的预定义标示符
assert (断言)
#define NDEBUG //即可取消断言
#include <cassert>
main(){
int c;
cin>>c;
assert(c);//c = 0 后者 false 时出现断言
cout<<1000/c;
}