V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
zynlp
V2EX  ›  C

这段代码为什么在 win 和 Linux 下结果不一样

  •  
  •   zynlp · Sep 19, 2018 · 5654 views
    This topic created in 2790 days ago, the information mentioned may be changed or developed.
    • win 下 vs2013 和 vs2017 结果是一样的
      a:
    • linux 下 g++ 4.8.5
      a: abc
    #include <iostream>
    
    using namespace std;
    
    struct A{
        const char* a;
    };
    
    void f(A* a){
        string s("abc");
        a->a = s.c_str();
    }
    
    int main(int argc, char* argv[]){
        A a;
        f(&a);
        printf("a: %s\n", a.a);
        return 0;
    }
    

    这属于 ub 的问题吗?

    25 replies    2018-09-20 00:34:50 +08:00
    zwzmzd
        1
    zwzmzd  
       Sep 19, 2018 via iPhone
    s 都随着函数 f 结束销毁了,再去用 c_str 本身就有问题
    zynlp
        2
    zynlp  
    OP
       Sep 19, 2018 via iPhone
    @zwzmzd 嗯,但是 linux 下还是会有 abc 的输出...
    ai277014717
        3
    ai277014717  
       Sep 19, 2018
    编译器内部实现不一样造成的吧
    seancheer
        4
    seancheer  
       Sep 19, 2018
    @zynlp 内存释放并不代表那块内存里面的内容会被写成 0,只是说这块内存可以被其他代码使用了。。你这个时候访问一块已经释放的内存虽然这会儿正常,但是不保证过一段时间还是正常的。。当程序规模比较大的时候,这块内存很有可能很快就被其他代码段使用了。

    这就是传说中踩内存中的一种情况。
    liangweijia6000
        5
    liangweijia6000  
       Sep 19, 2018   ❤️ 1
    这是想研究啥。。
    zivyou
        6
    zivyou  
       Sep 19, 2018
    会不会不同平台的垃圾清理方式不同导致的?比如 windows 中,在函数调用完之后,该函数的局部变量就被清理;而 Linux 将这个动作延迟到了进程退出(只是一种推测,我没有证实过)。
    dynamicheart
        7
    dynamicheart  
       Sep 19, 2018 via iPhone
    @zynlp 在 Linux 下,离开 f 作用域后,s 被销毁了,a 指向的是一个无效的地址空间,但因为这段内存空间还没有被复用,里面的数据还是 abc,所以打印出来的是 abc。
    zynlp
        8
    zynlp  
    OP
       Sep 19, 2018 via iPhone
    @seancheer 所以是 vs 里把这块内存给置 0,而 g++下没有置 0 的原因吗?
    disk
        9
    disk  
       Sep 19, 2018 via Android
    别这样,vs 安全检查比较严格,你不知道什么时候悬空
    wdlth
        10
    wdlth  
       Sep 19, 2018
    我在 Linux 下执行是返回乱码
    ipwx
        11
    ipwx  
       Sep 19, 2018
    这是未定义行为吧,你去理解它没有意义。
    Rosanta
        12
    Rosanta  
       Sep 19, 2018
    UB 有啥好研究的,你开不一样的优化等级输出还不一样呢
    rocbomb
        13
    rocbomb  
       Sep 19, 2018
    想起了大一 C 语言课本上的 a=(i++)*(i++)*(i++)*(i++)*(i++)*(i++);
    这种代码在工作中 谁写出来我非打死他不可
    seancheer
        14
    seancheer  
       Sep 19, 2018
    @zynlp 不一定啊。。和具体实现相关。具体就要找下 vc 和 linux 下的实现区别了。不过个人觉得死磕这个没有意义。
    你代码本身就是错误的行为,真正系统下是肯定会出问题的,无论 vc 还是 g++
    sbw
        15
    sbw  
       Sep 19, 2018
    学习一下 Rust 你就知道
    boris1993
        16
    boris1993  
       Sep 19, 2018 via iPad
    @rocbomb #13 这个........火刑柱伺候着
    codehz
        17
    codehz  
       Sep 19, 2018 via Android
    @rocbomb 把前面的 a 改成 i 更好(
    429839446
        18
    429839446  
       Sep 19, 2018
    请看 cppreference, c_str()这样用是未定义行为.
    shilyx
        19
    shilyx  
       Sep 19, 2018
    一楼说得对,代码错了,这是前提。

    错了的代码输出什么,只能回答:是什么就是什么,无任何保证。

    你汇编跟踪以下,也能搞清楚为什么会那样输出,一句话,各有各的道理,编译器不背锅。
    nutting
        20
    nutting  
       Sep 19, 2018
    g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16),编译不过去
    Apple LLVM version 7.3.0 (clang-703.0.29),编译后运行,输出乱码
    tourist2018
        21
    tourist2018  
       Sep 19, 2018
    @zivyou #6 和操作系统应该没关系 和编译器有关系 而且可以直接使用 printf 方法么?这不是 stdio.h 里面的库函数?
    wwqgtxx
        22
    wwqgtxx  
       Sep 19, 2018
    @tourist2018 有些编译器的 iostream 文件中会导入 cstdio 所以可以直接用
    neptuno
        23
    neptuno  
       Sep 19, 2018
    编译器不一样。有些未定义行为在不同编译器不一样的
    iceheart
        24
    iceheart  
       Sep 19, 2018 via Android
    这不是 ub,这是野指针
    msg7086
        25
    msg7086  
       Sep 20, 2018
    刚想说,这就是野指针啊。(然后楼上说了。)
    随便指向内存中一块不属于你的地址,出来的是啥就是啥。
    如果内核看你不爽,可以直接杀掉你的进程。如果他没那么凶,那就让你随便读点内存里的辣鸡数据。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1278 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 65ms · UTC 23:54 · PVG 07:54 · LAX 16:54 · JFK 19:54
    ♥ Do have faith in what you're doing.