1. C语言内存分区
C语言的内存分区没有域的概念,但是变量有静态(全局)与动态(局部)的分别,简单的说除了栈上的变量都是静态(全局)的。注意堆栈上的变量分配是动态的,但其实本身也是静态全局的。
- 全局变量:.rodata,.data,.bass,heap
- 局部变量:stack
- 函数:.text
在没有内存保护的前提下,在机器的视角上全局变量都是可见的,那么也就是说域或者作用域是为了组织高级语言代码而人为设置的一种边界。
2. C语言的域
C语言准确来说没有域,只有作用域的概念。
2.1 代码块作用域(block scope):
以一对大括号为边界。比如函数的大括号、if,while,switch,for的大括号、甚至可以凭空写一对大括号。
#include<stdio.h>
int main(void)
{
int i = 100; //i1
{
int i = 110; //i2
{
int i = 120; //i3
printf("i=%d\n", i);
//嵌套内部的会覆盖外部的同名变量,所以这里的120替代了外面的,打印出120
}
{
int i = 130; //i4
printf("i=%d\n", i); //又是另外一个作用域,相应的覆盖外面的值
}
printf("i=%d\n", i);
}
printf("i=%d\n", i);
return 0;
}
2.2 文件作用域(file scope):
以文件为边界的作用域。任何在代码块之外声明的标识符都具有文件作用域,作用范围是从他们的声明位置开始,到文件的结尾处都是可以访问的
函数名也具有文件作用域,因为函数名本身也是在代码块之外。
2.3 包含方式
使用#include,以文件作用域进行包含
3. C++语言的域
由于C++是C语言的超集,因此C语言的所有特性在C++中依然有,但是有所增加
3.1 命名空间作用域(namespace scope):
命名空间作用域是指在一个命名空间内可见的作用域,可以通过命名空间来组织和管理代码,避免命名冲突。使用using namespace可以简化之后的调用。
#include <iostream>
using namespace std;
// 第一个命名空间
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
}
// 第二个命名空间
namespace second_space{
void func(){
cout << "Inside second_space" << endl;
}
}
int main ()
{
// 调用第一个命名空间中的函数
first_space::func();
// 调用第二个命名空间中的函数
second_space::func();
return 0;
}
其中特殊的全局作用域(文件作用域)用::表示(或者什么都不写),即不在任何namespace中(extern "C"作用域都在全局作用域(文件作用域)中)。
extern "C" {
void cFunction(); // 声明一个C语言函数
}
namespace MyNamespace {
void myFunction() {
// 在命名空间中使用C语言函数
::cFunction();
}
}
int main() {
MyNamespace::myFunction();
return 0;
}
3.2 类作用域(class scope):
类作用域是指在一个类内部可见的作用域,包括类的成员变量、成员函数和成员类型。
#include <iostream>
class MyClass {
public:
static int staticVariable; // 类作用域的静态变量
int instanceVariable; // 类作用域的实例变量
static void staticFunction() {
std::cout << "This is a static function." << std::endl;
}
void instanceFunction() {
std::cout << "This is an instance function." << std::endl;
}
};
int MyClass::staticVariable = 10; // 类作用域的静态变量的定义和初始化
int main() {
MyClass::staticVariable = 20; // 类作用域的静态变量的访问和修改
std <<staticVariable << std::endl;
MyClass myObject;
myObject.instanceVariable = 30; // 类作用域变量的访问和修改
std::cout << "Instance variable: " << myObject.instanceVariable << std::endl;
MyClass::staticFunction(); // 类作用域的静态函数的调用
myObject.instanceFunction(); // 类作用域的实例函数的调用
return 0;
}
3.3 包含方式
使用#include,以文件作用域进行包含。
C++20引入了import,以模块方式包含(建议C++换个名字,另起炉灶吧)
3. C#语言的域
3.1 作用域
基本与C++相同,但是域的符号使用.,而并非::。而且最不同的一点是C#没有全局作用域的概念,也就是说所有的函数和变量必须在某个类作用域内,类作用域又必须在某个命名空间里:
namespace name
{
class Program
{
static void Main(string[] args)
{
}
}
}
3.2 包含方式
与C和C++完全不同,包含的是名字空间(不包含使用的时候写全称也可以)
using System; // 引入System命名空间
namespace MyNamespace
{
class MyClass
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!"); // 可以直接使用Console类,而无需写成System.Console
}
}
}
4. 总结
作用域:
-
命名空间级作用域:C#独有的概念,命名空在空间内部定义的作用域。在命名空间级用域中定义的变量、常量、方法和类型可以在整个命名空间内部访问。而在C和C++中,没有类似的命名空间概念。
-
类级作用域:C++和C#都支持类级作用域,即在类内部定义的作用域。在类级作用域中定义的变量、常量、方法和访问。而在C中,没有类的概念,因此没有类级作用域。
-
文件级作用域:C和C++都支持文件级作用域,即在文件内部定义的变量、常在整个文件内部访问。而在C#中,文件级作用域的概念没有明确的表达方式,所有的代码都必须位于类或命名空间中。
文件包含:
- C和C++:使用预处理器指令#include来包含文件。这个指令告诉预处理器在编译前将整个被包含文件的内容插入到该指令的位置被包含的文件通常是头了函数声明、宏定义等信息。
- C#:C#没有类似C器令需要使用其他文件中的类或方法,一般通过命名空间(namespace)来组织和引用。使用using关键字可以引入其他命名空间中的类,从而避免写出全限定名
总之,越现代的语言对于作用域的要求越严格,对于文件包含的要求越宽松。文件包含逐渐突破文本级别的替换,向语义级别发展。