• 在 C# CLR 中学习 C++ 之了解 namespace



    ## 一:背景

    相信大家在分析 dump 时,经常会看到 `WKS` 和 `SRV` 这样的字眼,如下代码所示:

    ``` C#

    00007ffa`778a07b8 coreclr!WKS::gc_heap::segment_standby_list = 0x00000000`00000000
    00007ffa`778a3870 coreclr!WKS::qpf = 0x989680
    00007ffa`7789da30 coreclr!SVR::heap_select::numa_node_to_heap_map = unsigned short [1028]
    00007ffa`7789f2d0 coreclr!SVR::gc_heap::should_expand_in_full_gc = 0n0

    ```

    其实这就是命名空间,即 coreclr 在编译源码的时候,为 `WKS` 和 `SVR` 各编译了一份,不知道这么做的初衷是什么,这里就不管了,接下来看下 coreclr 中大概长啥样子。


    ``` C#

    namespace WKS {
        #include "gcimpl.h"
        #include "gc.cpp"
    }

    namespace SVR {
        #include "gcimpl.h"
        #include "gc.cpp"
    }

    ```

    ## 二:聊一聊 namespace


    其实和 C# 的 namespace 本质差不多,都是起到隔离的作用,而且和 using 的配合使用和 C# 也是如出一辙,太有意思了。

    ### 1. 简单的隔离

    在 C++ 中默认只有一个 namespace,所以相同的变量会出现冲突,解决办法就是用 namespace 隔离,参考如下代码:

    ``` C++

    namespace WKS
    {
        int a = 10;
        int b = 11;
    }

    namespace SRV {

        int a = 100;
        int b = 101;
    }

    int main()
    {
        printf("WKS::a= %d \n", WKS::a);
        printf("SRV::a= %d \n", SRV::a);
    }

    ```

    ![](https://hxc-test.oss-cn-hangzhou.aliyuncs.com/PYZ/20220829231511.png)


    当然还可以嵌套使用,比如改成这样。


    ``` C++

    namespace WKS
    {
        namespace V1 {
            int a = 10;
            int b = 11;
        }
    }

    int main()
    {
        printf("WKS::a= %d \n", WKS::V1::a);
    }

    ```

    接下来看下汇编代码:

    ![](https://hxc-test.oss-cn-hangzhou.aliyuncs.com/PYZ/20220829231915.png)

    哈哈,看到上面的 `WKS::V1::a` 感觉是不是挺舒服的,也特能理解目前的 `coreclr!WKS::xxx` 了, 不过这里有一个麻烦的地方,就是每次用 `a` 的时候都要输入很长的前缀,那有没有简化的方法呢? 当然有啦。

    ### 2. 使用 using 导入


    接下来我们用 using 直接在 main 函数中定义字段,后续就不需要再写长长的前缀引用了,参考代码如下:

    ``` C++

    namespace WKS
    {
        namespace V1 {
            int a = 10;
            int b = 11;
        }
    }

    int main()
    {
        using WKS::V1::a;

        printf("WKS::V1::a1= %d \n", a);
    }

    ```

    ![](https://hxc-test.oss-cn-hangzhou.aliyuncs.com/PYZ/20220829233323.png)


    ### 3. 使用 using 定义别名


    定义别名这功能特别好,个人感觉已经完全替代以前的 `typedef` 功能,比如下面的代码是完全一样的。

    ``` C++

    int main()
    {
        typedef const char* PCHAR;

        using PCHAR2 = const char*;

        PCHAR ptr1 = "hello world1";

        PCHAR2 ptr2 = "hello world2";
    }

    ```

    如果还不信的话,可以看下它们各自生成的汇编代码。


    ``` C++

        PCHAR ptr1 = "hello world1";
    00007FF79856183B  lea         rax,[string "hello world1" (07FF798569C10h)]  
    00007FF798561842  mov         qword ptr [ptr1],rax  

        PCHAR2 ptr2 = "hello world2";
    00007FF798561846  lea         rax,[string "hello world2" (07FF798569CE8h)]  
    00007FF79856184D  mov         qword ptr [ptr2],rax  

    ```

    ### 4. 使用 using namespace 导入


    这个是最普遍的,我们对系统库的调用,无一不是用 using namespace 方式的,比如下面的代码。


    ``` C++

    using namespace std;

    int main()
    {
        string str = "hello world";
    }

    ```

    接下来我们把 V1 导入到 main 方法中,这样就可以自由自在的使用 `WKS::V1` 中的内容了,参考如下代码:


    ``` C#

    namespace WKS
    {
        namespace V1 {
            int a = 10;
            int b = 11;
        }
    }

    int main()
    {
        using namespace WKS::V1;

        printf("a=%d, b=%d", a, b);
    }

    ```

    ![](https://hxc-test.oss-cn-hangzhou.aliyuncs.com/PYZ/20220829234533.png)

    好了,这就是对 namespace 的一点理解,本篇就说这么多吧,希望对你有帮助。

  • 相关阅读:
    使用Flume采集日志数据到HDFS中
    设备启动顺序导致OpenWrt找不到网卡错误
    springboot 2.6.6启动原理
    spring-cloud-alibaba-dubbo-issues1805修复
    Transformers.js v2.6 现已发布
    springboot上传文件到后台指定文件夹
    竞赛选题 基于机器视觉的行人口罩佩戴检测
    通信世界扫盲基础二(原理部分)
    leetcode - 1293. Shortest Path in a Grid with Obstacles Elimination
    达梦数据库查看锁以及解锁
  • 原文地址:https://blog.csdn.net/huangxinchen520/article/details/126640521