用php做的大型网站有哪些,什么公司做网站好,铁路建设网站多少,深圳福田最新消息今天文章目录 前提正文多重定义extern关键字使用staticstatic 全局变量(在.cpp文件中定义)static变量存放在哪里static变量可不可以放在.h文件中 static 函数static局部变量static 成员变量static 成员函数 总结参考链接 前提
好吧#xff0c;八股#xff0c;我又回来了。这次想… 文章目录 前提正文多重定义extern关键字使用staticstatic 全局变量(在.cpp文件中定义)static变量存放在哪里static变量可不可以放在.h文件中 static 函数static局部变量static 成员变量static 成员函数 总结参考链接 前提
好吧八股我又回来了。这次想探究下static关键字因为用到过同时对下面的有些问题还不是很清楚
static变量都有什么static关键字的作用
正文
在开始研究static之前我想先引导几个问题这几个问题对接下来理解static有一定的作用。
多重定义
有test.h, test.cpp, main.cpp三个文件如下
/*test.h*/
#ifndef TEST_H_
#define TEST_H_int a 5; /*这是重点*/
void print();#endif/*test.cpp*/
#includetest.h
#includeiostreamvoid print()
{std::couthello, world\n;
}/*main.cpp*/
#include iostream
#include test.hint main()
{print();std::couta: astd::endl;
}程序说明在test.h定义了一个int的变量a我们想在main.cpp中输出这个a使用gcc进行编译。 运行结果编译出错出错信息如下 可以看到是链接期间的错误多重定义。
我们分析下为什么会出现这个错误。
首先明白程序编译的过程。 将源代码编译为可执行文件有四个阶段预处理——编译——汇编——链接。预处理大概做的是define定义的替换include文件的拷贝比如说main.cpp中include了test.h编译器会将test.h的内容拷贝到main.cpp中等等编译大概做的是将C代码编译为汇编代码汇编大概做的是将汇编代码编译为机器码链接大概做的是将所有cpp文件编译的机器码合并为一个可执行文件。大概来说就是这样详细的大家可以自行百度。这里我们先关注预处理阶段。它会将test.h的内容拷贝到main.cpp中那么此时相当于已经在main.cpp中有了int a 5这个定义有了a这个变量如果没有a这个变量编译器会直接报错找不到a。然后对于test.cpp它也include了test.h所以test.cpp中也有了int a 5这个定义有了a这个变量。接下来两个cpp分别进行编译汇编。到了链接阶段(上面的错误就发生在链接阶段)它将main.cpp的机器码和test.cpp的机器码合并到一起但main中a的定义test中有a的定义所以就会出现多重定义的这个错误。
举这个例子是想给大家说明程序编译的过程。接下来我们使用extern关键字改写这个程序。
extern关键字
/*test.h*/
#ifndef TEST_H_
#define TEST_H_
void print();#endif/*test.cpp*/
#includetest.h
#includeiostreamint a 5;
void print()
{a a1;std::couta: astd::endl;
}/*main.cpp*/
#include iostream
#include test.h
extern int a;
int main()
{a a1;std::couta: astd::endl;print();
}程序说明在test.cpp中定义一个全局变量a然后在main.cpp中想使用这个变量a这里我们借助了extern这个关键字表明这只是a的声明它在其它地方定义(在test.cpp中定义)。 运行结果如下所示。 按照上面的分析过程自已分析下。
使用static
我们见到的static大概有以下几类
static 全局变量static 局部变量static 成员变量static 函数static 成员函数
static 全局变量(在.cpp文件中定义)
改写代码如下
/*test.h*/
#ifndef TEST_H_
#define TEST_H_void print();
#endif/*test.cpp*/
#includetest.h
#includeiostream
static int a 5;
void print()
{a a1;std::couta: astd::endl;
}/*main.cpp*/
#include iostream
#include test.h
// extern int a; # 重点关注
int main()
{print();std::coutastd::endl;
}程序说明在test.cpp中定义了一个static变量a然后print()函数使用了这个变量最后在main.cpp中调用print()函数。 运行结果 这里重点关注main.cpp中注释的这行代码extern int a。从上面可知extern的作用是告诉编译器我的这个a只是声明你链接的时候在其它地方去找。 而一但我们使用static来定义这个变量时该变量就只在test.cpp中可见也就是对其它的cpp文件隐藏这时如果我们在main.cpp中使用extern编译器还是找不到变量a的定义。运行结果如下
所以这就是static的第一个作用隐藏。static声明的全局变量只在该文件内可见对其它文件是不可见的。
隐藏这个特点会带来什么好处呢
利用这一特点可以在不同的文件中定义同名变量而不必担心命名冲突。 明白这一点后我们在来看一些小问题
static变量存放在哪里
先来看看现代操作系统中一个进程的内存空间布局 Text section: 存放二进制指令。 Data section: 存放非0初始化的静态数据和全局变量。 BSS (Block Started by Symbol): 存放0初始化的静态数据和全局变量程序中没有初始化的静态数据会被初始为0并存放到这里。 Heap: 存放动态分配的数据。 Stack: 存放局部变量函数参数指针等。 来吧让我们继续。C的内存分布有的人说C没有标准的内存分布和上面的基本一致只不过显式指出了有一个**只读数据区(.rodata)**用来存放全局常量数据(const)如下 回归正题我们采用一些方法来确认static全局变量存放在**.bss section**未初始化和**.data section**初始化。
先来确定初始化的static变量存放在.data中。 有以下代码
static int variable_a10; // 全局static变量已初始化为10
int main()
{}这里要借助objdump这个命令。objdump 是一个功能强大的命令行工具用于显示二进制文件如可执行文件、目标文件和共享库的各种信息。它是GNU Binutils软件包的一部分广泛用于调试、分析和逆向工程。通过 objdump用户可以查看文件头、段表、符号表、反汇编代码等详细信息。 编译程序然后使用objdump -t显示符号表如下 可以看到初始化的static变量存放在.data中。 再来确定未初始化的static变量存放在.bss中。修改代码如下
#includestdio.h
static int variable_a;
int main()
{printf(variable_a: %d\n, variable_a); // 验证未初始化的static变量会被编译器初始化为0全局变量也一样
}结果如下 然后使用objdump查看符号表 可以看到未初始化的static变量存放在.bss中。 再来确定初始化为0的static变量也存放在.bss中。 修改代码如下
#includestdio.h
static int variable_a0;
int main()
{printf(variable_a: %d\n, variable_a); // 验证未初始化的static变量会被编译器初始化为0
}如下 可以看到初始化为0的static变量存放在.bss中。
static变量可不可以放在.h文件中
代码如下
/*test.h*/
#ifndef TEST_H_
#define TEST_H_static int variable_a 5; // 重点关注将static变量定义在.h中
void func();#endif/*test.cpp*/
#includetest.h
#includeiostreamvoid func()
{variable_a 5; // // test.cpp 中的static int variable_a 加2std::couttest.cpp: variable_a variable_a std::endl;
}/*main.cpp*/
#includeiostream
#includetest.h
int main()
{variable_a 2; // main.cpp 中的static int variable_a 加2std::cout main.cpp: variable_a variable_a std::endl;func();
}程序说明将static变量定义在test.h中然后在main.cpp中包含test.h。 运行结果 结果说明了main.cpp中的variable_a和test.h中的variable_a是两个独立的变量。因为它们都是static变量而static变量有隐藏的特性所以它们互相对对方隐藏。
static 函数
static函数和static全局变量一样都有隐藏的作用所以允许同名函数。代码如下
/*test.h*/
#ifndef TEST_H_
#define TEST_H_static void print();
void use_print();#endif/*test.cpp*/
#includetest.h
#includeiostreamvoid print()
{std::couthello static, test.cppstd::endl;
}void use_print()
{print();
}/*main.cpp*/
#includeiostream
#includetest.hvoid print()
{std::couthello static, main.cppstd::endl;
}int main()
{print();use_print();
}程序说明在test.cpp中定义了一个static函数print()同时在main.cpp中定义了一个同名函数print()。按照我们的分析static函数只在test.cpp中可见所以使用main.cpp包含test.h后main.cpp是看不见test.h中的print()函数的。可以编译运行结果如下
static局部变量
static修饰局部变量时使得该变量不会因为函数运行结束而丢失使其生命周期为整个源程序。把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域 限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。
代码如下
/*main.cpp*/
#includeiostreamint fun()
{static int variable_a 10; // //在第一次进入这个函数的时候variable_a被初始化为10。接着每次调用fun()variable自加1在static发明前要达到同样的功能则只能使用全局变量 variable_a;return variable_a;
}int main()
{for(int i0; i10; i){std::cout variable_a: fun() std::endl;}
}结果
static 成员变量
代码如下
/*main.cpp*/
#includeiostreamclass Base{
public:Base() default;virtual ~Base() default;
public:static int variable; /* 类内定义 */
};int Base::variable 10; /* 类外初始化 */int main()
{std::coutBase::variable Base::variablestd::endl;
}这段代码肯定是可以编译运行的在这里我们要思考的问题是为什么类的静态成员变量要类内定义类外初始化 有一个理论答案**因为静态成员属于整个类而不属于某个对象如果在类内初始化会导致每个对象都包含该静态成员这是矛盾的。**如果你在类内初始化编译会报错信息如下 这里埋个坑可不可以从代码层面分析为什么不能这么做 static 成员函数
**static成员函数和static成员变量属于类不属于类的某个对象。**所以static成员函数只能调用static 成员函数和static成员变量。
代码如下
/*main.cpp*/
#includeiostreamclass Base{
public:Base() default;virtual ~Base() default;
public:static int variable_a; /* 类内定义 */int a; /* 普通成员变量 */void func1(){std::coutthis func1 is a member functionstd::endl;}static void func(){ a 4; // error: invalid use of member Base::a in static member functionfunc1(); // error: cannot call member function void Base::func1() without objectstd::coutvariable_a: variable_a std::endl;}
};int Base::variable_a 10; /* 类外初始化 */int main()
{Base base;base.func();Base::func();
}程序说明在static成员函数中调用普通成员函数和普通成员变量。 结果程序编译出错如下 类的静态成员函数是属于整个类而非类的对象所以它没有this指针这就导致它仅能访问类的静态数据和静态成员函数。
总结
关于static关键字暂时总结这么多当然关于static还有更多的问题接下来遇到再更新。
参考链接
https://blog.csdn.net/u011718663/article/details/118218407https://www.cnblogs.com/honernan/p/14478366.html