c++ cmake 动态库的 std::string 为空,求指点(maocs-12.6) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
datadump
V2EX    C++

c++ cmake 动态库的 std::string 为空,求指点(maocs-12.6)

  •  
  •   datadump 2023-07-17 15:52:45 +08:00 2023 次点击
    这是一个创建于 881 天前的主题,其中的信息可能已经有所发展或是发生改变。
    https://github.com/wjx0912/cmake_macos_cpptest

    https://github.com/wjx0912/cmake_macos_cpptest/raw/main/screenshot.png

    万分感谢

    20 条回复    2023-07-17 17:32:22 +08:00
    datadump
        1
    datadump  
    OP
       2023-07-17 16:17:24 +08:00
    猜测的原因:__attribute__((constructor))时,c++ runtime 还未初始化,std::string 的一些操作可能不稳定。

    测试:
    ```
    std::string g_test1;
    std::string g_test2;

    __attribute__((constructor))
    static void init() {
    g_test1 = "hello test1";
    printf("init: %s\n", g_test1.c_str());
    }

    void hello_func1(void) {
    g_test2 = "hello test2";
    printf("Hello World: %s, %s\n", g_test1.c_str(), g_test2.c_str());

    return;
    }

    void hello_func2(void) {
    printf("Hello World: %s, %s\n", g_test1.c_str(), g_test2.c_str());

    return;
    }
    ```

    在 hello_func2 里面,g_test1 无法打印,g_test2 正常。

    不知道这个思路是否正确,求大神指点
    chingyat
        2
    chingyat  
       2023-07-17 16:36:56 +08:00
    应该是 init() 在 g_test 初始化之前就被调用了。
    datadump
        3
    datadump  
    OP
       2023-07-17 16:37:17 +08:00
    ```
    搞定了,把:
    std::string g_test1;
    std::string g_test2;
    改成:
    __attribute__((init_priority(101))) std::string g_test1;
    __attribute__((init_priority(101))) std::string g_test2;

    参考:
    https://stackoverflow.com/questions/43941159/global-static-variables-initialization-issue-with-attribute-constructor-i
    ```
    chingyat
        4
    chingyat  
       2023-07-17 16:38:28 +08:00
    ```c++
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <string>

    #include "hello.h"

    std::string g_test = "initial value";

    __attribute__((constructor))
    static void init()
    {
    g_test = "hello test";
    printf("init: %s\n", g_test.c_str());
    }

    void hello_func(void) {
    printf("Hello World: %s\n", g_test.c_str());

    return;
    }
    ```

    执行结果:

    ```
    init: hello test
    Hello World: initial value
    ```
    datadump
        5
    datadump  
    OP
       2023-07-17 16:39:33 +08:00
    这个不是编译器 bug ,是未指定行为
    Shatyuka
        6
    Shatyuka  
       2023-07-17 16:40:30 +08:00
    `__attribute__((constructor))`在全局变量初始化之前执行。试试给全局变量添加`__attribute__((init_priority(101)))`属性。
    datadump
        7
    datadump  
    OP
       2023-07-17 16:41:28 +08:00
    @chingyat 嗯。这个是没问题的。但是 g_test 不是固定值(会从文本读取)。runtime 执行一堆 constructor 的顺序问题。
    datadump
        8
    datadump  
    OP
       2023-07-17 16:42:39 +08:00
    @Shatyuka 正解。谢谢
    datadump
        9
    datadump  
    OP
       2023-07-17 16:44:12 +08:00
    @Shatyuka windows 的 DllMain.DLL_PROCESS_ATTACH 执行的比较晚,所以不会有这个问题,对吧
    yulon
        10
    yulon  
       2023-07-17 16:44:22 +08:00
    这个问题和 DllMain 一样,在大部分实现上,C 的部分一般比 C++ 运行时要早或者说更底层运行,不要使用 C 方言,不要混用 C/C++ 关于生存周期的部分。
    zpd2009
        11
    zpd2009  
       2023-07-17 16:47:18 +08:00
    反汇编看了一下,在.init_array 段,执行完 init 以后,又执行了一个函数,把 g_test1 和 g_test2 又初始化为了空
    yulon
        12
    yulon  
       2023-07-17 16:49:35 +08:00
    @yulon MSVC 在 DllMain 里使用 C++ 标准库部分功能会炸或者死锁,Mingw-w64 GCC 相对安全一点,因为包了另一套东西,但是微软一直推荐不要在 DllMain 中执行太复杂的操作,DLL 的核心功能应该放在导出函数中。
    zpd2009
        13
    zpd2009  
       2023-07-17 16:54:48 +08:00
    如果 g_test1 指定了__attribute__((init_priority(101))),在.init_array 段执行的最后一个函数里,只初始化了 g_test2 ,没有重新初始化 g_test1
    datadump
        14
    datadump  
    OP
       2023-07-17 16:58:45 +08:00
    datadump
        15
    datadump  
    OP
       2023-07-17 17:00:15 +08:00
    @zpd2009 谢谢。还是运行时没完全理解。但这种坑对新手实在是不友好
    ysc3839
        16
    ysc3839  
       2023-07-17 17:13:30 +08:00 via Android
    @wjx0912 #9 不是,DllMain 是最早执行的,但是 CRT 会在执行用户的 DllMain 之前先执行初始化代码。
    yulon
        17
    yulon  
       2023-07-17 17:17:51 +08:00
    @wjx0912 我说整个标准库,又不是单纯的 std::string ,还有语言层面的特性(线程安全保证之类的)有很多 MSVC 直接用标准库来实现,这种碰到了都会炸
    datadump
        18
    datadump  
    OP
       2023-07-17 17:18:44 +08:00
    @ysc3839 谢谢
    yulon
        19
    yulon  
       2023-07-17 17:25:26 +08:00
    @wjx0912 还有你这个测试,是在同一个编译单元内,一般来说同编译单元在编译时初始化顺序就决定了,这个很好优化,不同编译单元的初始化顺序是完全不可预料的,链接器可能会帮你排好序,但是遇到冲突是不可能完全按照你预料的顺序来初始化,只有 C++ 运行时完全初始化后,才能保证所有全局变量都初始化了。
    lts9165
        20
    lts9165  
       2023-07-17 17:32:22 +08:00
    std::string& get_test1() {
    static std::string test1;
    return test1;
    }

    std::string& get_test2() {
    static std::string test2;
    return test2;
    }

    __attribute__((constructor))
    static void init() {
    get_test1() = "hello test1";
    printf("init: %s\n", get_test1().c_str());
    }

    void hello_func1(void) {
    get_test2() = "hello test2";
    printf("Hello World: %s, %s\n", get_test1().c_str(), get_test2().c_str());

    return;
    }

    void hello_func2(void) {
    printf("Hello World: %s, %s\n", get_test1().c_str(), get_test2().c_str());

    return;
    }


    这是 chatgpt 给出的方案
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3833 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 05:18 PVG 13:18 LAX 21:18 JFK 00:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86