首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
华为云
V2EX  ›  C/C++/Obj-C

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

  •  
  •   zynlp · 60 天前 · 2843 次点击
    这是一个创建于 60 天前的主题,其中的信息可能已经有所发展或是发生改变。
    • 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 回复  |  直到 2018-09-20 00:34:50 +08:00
        1
    zwzmzd   60 天前 via iPhone
    s 都随着函数 f 结束销毁了,再去用 c_str 本身就有问题
        2
    zynlp   60 天前 via iPhone
    @zwzmzd 嗯,但是 linux 下还是会有 abc 的输出...
        3
    ai277014717   60 天前
    编译器内部实现不一样造成的吧
        4
    seancheer   60 天前
    @zynlp 内存释放并不代表那块内存里面的内容会被写成 0,只是说这块内存可以被其他代码使用了。。你这个时候访问一块已经释放的内存虽然这会儿正常,但是不保证过一段时间还是正常的。。当程序规模比较大的时候,这块内存很有可能很快就被其他代码段使用了。

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

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

    你汇编跟踪以下,也能搞清楚为什么会那样输出,一句话,各有各的道理,编译器不背锅。
        20
    nutting   60 天前
    g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16),编译不过去
    Apple LLVM version 7.3.0 (clang-703.0.29),编译后运行,输出乱码
        21
    tourist2018   60 天前
    @zivyou #6 和操作系统应该没关系 和编译器有关系 而且可以直接使用 printf 方法么?这不是 stdio.h 里面的库函数?
        22
    wwqgtxx   60 天前
    @tourist2018 有些编译器的 iostream 文件中会导入 cstdio 所以可以直接用
        23
    neptuno   60 天前
    编译器不一样。有些未定义行为在不同编译器不一样的
        24
    iceheart   59 天前 via Android
    这不是 ub,这是野指针
        25
    msg7086   59 天前
    刚想说,这就是野指针啊。(然后楼上说了。)
    随便指向内存中一块不属于你的地址,出来的是啥就是啥。
    如果内核看你不爽,可以直接杀掉你的进程。如果他没那么凶,那就让你随便读点内存里的辣鸡数据。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1948 人在线   最高记录 3821   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.1 · 17ms · UTC 10:23 · PVG 18:23 · LAX 02:23 · JFK 05:23
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1