zynlp
V2EX  ›  C

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

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

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

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

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