V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
v2byy
V2EX  ›  C

下面的代码为什么赋值之后不对

  •  
  •   v2byy · 2018-09-11 16:44:43 +08:00 · 4408 次点击
    这是一个创建于 2267 天前的主题,其中的信息可能已经有所发展或是发生改变。

    https://i.loli.net/2018/09/11/5b977fcb2e371.png

    赋值之后:

    https://i.loli.net/2018/09/11/5b977fcb3515e.png

    func_name 为字符串"wait", 但是赋值之后却不是这个值

    相关声明如下:

    
    typedef struct _local_func {
    	const char *func_name;	// function name
    	lua_CFunction func_ptr;	// function pointer
    	const char *help_info;	// help information for this function
    } LOCAL_FUNC;
    
    LOCAL_FUNC g_local_func;
    
    
    第 1 条附言  ·  2018-09-12 09:24:19 +08:00

    不好意思,g_local_func是一个array,笔误。

    LOCAL_FUNC g_local_func[];
    
    //context here
    bool init_plugins(lua_State* L){
        //...
        const char* func_name = g_local_func[i].func_name;
        lua_CFunction func_pt = g_local_func[i].func_ptr;
        const char* help_info = g_local_func[i].help_info;
    }
    
    
    

    我在c代码中定义了一个g_local_func结构体数组,然后定义了一个init_plugins方法,在c中调用这个方法时如上面图片所示,g_local_func是有值的,但是赋值给函数中的局部变量的时候,却无法正确获取到值。

    这个跟lua通过栈来传递参数应该没有关系吧,因为我是在c中调用的这个函数,g_local_func是一个全局的变量。

    第 2 条附言  ·  2018-09-12 16:25:04 +08:00

    我把代码提取了一下。希望大佬解惑。

    file: TestStudent.cpp

    #include "stdafx.h"
    #include "TestStudent.h"
    
    extern const int NUM;
    extern Student allStudents[];
    
    
    void print_student(){
    	for (int i = 0; i < NUM; ++i){
    
    		auto first_name = allStudents[i].first_name;  //not working, why?
    		auto last_name = allStudents[i].last_name;  //last_name is NULL?
    
    		std::cout << first_name << " " << last_name << std::endl;
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
    	print_student();
    
    	return 0;
    }
    
    

    file: source.cpp

    #include "stdafx.h"
    #include "TestStudent.h"
    
    const int NUM = 3;
    
    
    static Student* get_all_students(){
    
    	Student* ss = new Student[NUM];
    	Student* ptr = ss;
    
    	for (int i = 0; i < NUM; ++i){
    		
    		ptr->first_name = "test1";
    		ptr->last_name = "test2";
    		++ptr;
    	}
    
    	return ss;
    	
    }
    
    Student* allStudents = get_all_students();
    

    file: TestStudent.h

    #pragma once
    
    typedef struct _student{
    	const char* first_name;
    	const char* last_name;
    } Student;
    
    extern const int NUM;
    
    37 条回复    2018-09-13 17:55:47 +08:00
    Dori
        1
    Dori  
       2018-09-11 17:32:00 +08:00
    踩踩
    coderluan
        2
    coderluan  
       2018-09-11 17:35:43 +08:00
    ->
    raysonx
        3
    raysonx  
       2018-09-11 19:00:34 +08:00 via Android
    代码看起来没有问题,不过我好奇的是 g_local_func 看起来是一个结构体变量,你是怎么应用下标的?
    kljsandjb
        4
    kljsandjb  
       2018-09-11 19:41:39 +08:00 via iPhone
    上下文感觉不够啊…看不出来,还有 g_local_func 是个结构体数组?不一样至少说明 func_name 指向的内存被破坏了吧?看看栈有没有被破坏或者如果你是分配在堆上的话,是不是内存管理出了问题😂
    bp0
        5
    bp0  
       2018-09-11 21:49:33 +08:00
    g_local_func 不是数组吧,怎么看都只是一个全局变量而已。去掉[i]试试看。
    si
        6
    si  
       2018-09-11 22:07:16 +08:00
    猜不到是怎么赋值的
    inoki
        7
    inoki  
       2018-09-11 22:22:22 +08:00 via Android
    lua interpreter 源代码?
    Deville
        8
    Deville  
       2018-09-11 23:38:55 +08:00 via iPhone
    只能看得出是 vs 2017....
    zyp0921
        9
    zyp0921  
       2018-09-12 09:03:31 +08:00
    这是 C 语言吧
    v2byy
        10
    v2byy  
    OP
       2018-09-12 09:24:41 +08:00
    @raysonx 笔误,已 append
    v2byy
        11
    v2byy  
    OP
       2018-09-12 09:27:07 +08:00
    @kljsandjb 恩,我是通过 malloc 来给 g_local_func 分配的内存,是这样的,我使用在 c 文件中声明并给 g_local_func 分配内存,然后在另外一个 c 文件中通过 extern 导入 g_local_func 变量,然后调用的这个方法。
    v2byy
        12
    v2byy  
    OP
       2018-09-12 09:27:32 +08:00
    @bp0 笔误了,已 append
    v2byy
        13
    v2byy  
    OP
       2018-09-12 09:29:11 +08:00
    @inoki 不是哦,export 一些函数给 lua 用而已。
    v2byy
        14
    v2byy  
    OP
       2018-09-12 09:30:24 +08:00
    @Deville 怎么看出 vs2017 的?

    @zyp0921 源代码是 c++
    wutiantong
        15
    wutiantong  
       2018-09-12 09:33:56 +08:00
    @v2byy 看起来不会有你所说的“赋值不对”的问题,建议你直接 printf(%s, %p)出来看看?
    tusj
        16
    tusj  
       2018-09-12 09:38:37 +08:00
    感觉是乌龙
    ipwx
        17
    ipwx  
       2018-09-12 10:07:43 +08:00 via iPhone
    用 *g_local_func
    raysonx
        18
    raysonx  
       2018-09-12 10:47:51 +08:00
    从楼主给出的上下文中看不出任何问题,怀疑:
    1. 调试器故障。
    2. 编译器故障。
    3. 多线程运行,全局数组被覆盖。
    v2byy
        19
    v2byy  
    OP
       2018-09-12 16:25:39 +08:00
    @tusj 请看下 append
    v2byy
        20
    v2byy  
    OP
       2018-09-12 16:26:03 +08:00
    @raysonx 没有这么复杂,感觉是我理解的有问题,但是不知道在哪?
    innoink
        21
    innoink  
       2018-09-12 16:35:57 +08:00 via Android   ❤️ 1
    你把 extern Student allStudents[]改成 extern Students* allStudents
    kidtest
        22
    kidtest  
       2018-09-12 16:44:58 +08:00   ❤️ 1
    file: TestStudent.cpp

    #include "stdafx.h"
    #include "TestStudent.h"

    extern const int NUM;
    extern Student allStudents[];

    最后一行修改为:extern Student* allStudents 即可。

    另外记得释放内存
    v2byy
        23
    v2byy  
    OP
       2018-09-12 17:02:31 +08:00
    @innoink
    @kidtest

    多谢,但是为什么会出现这个问题呢?
    innoink
        24
    innoink  
       2018-09-12 17:11:06 +08:00 via Android
    @v2byy 类型不匹配。
    innoink
        25
    innoink  
       2018-09-12 17:17:29 +08:00 via Android
    @v2byy 链接过程是不做类型检查的,你想一下数组和指针变量的区别,指针额外占用一块内存保存地址,你把他声明为数组的话,连接器找到 allStudents 这个符号,会认为这就是数组首地址,即认为这个符号后面的数据就是数组内容。
    innoink
        26
    innoink  
       2018-09-12 17:22:40 +08:00 via Android
    或者你想一下,如果是真的有个 allStudents[],比如有个 Students allStudents[10],那么你 extern Students allStudents[],和你以前的写法之间的区别。
    gnaggnoyil
        27
    gnaggnoyil  
       2018-09-12 18:29:11 +08:00
    您可能是 array to pointer decay 的受害者
    raysonx
        28
    raysonx  
       2018-09-12 18:37:23 +08:00 via Android
    @innoink 但这并不能解释为何那条本地变量的的赋值结果会发生变化。我怀疑是因为调试器解析符号的行为和链接器实际链接的行为不一致,导致调试器里看到的=后面的值是错误的。
    v2byy
        29
    v2byy  
    OP
       2018-09-12 18:50:53 +08:00 via iPhone
    @innoink 太感谢了
    v2byy
        30
    v2byy  
    OP
       2018-09-12 18:55:50 +08:00 via iPhone
    @raysonx 是不是其实调试器显示的 allStudent[i].first-name 其实是错的,赋值操作其实是对的
    raysonx
        31
    raysonx  
       2018-09-12 19:16:39 +08:00
    @v2byy 我的理解是:
    不能简单的说对不对吧。大概就是 allStudents 的声明和实现不一致(声明为数组,实际为指针)。

    调用方( TestStudent.cpp )只能看到头文件,看不到具体实现,把 allStudents 当成了数组,于是 allStudents[i]被编译为了指针的值向后偏移,即*(allStudents + i),造成访问越界。

    调试器的行为目测与编译器不一致,它把 allStudents 视为一个指针,将 allStudents[i]解析为 allStudents 所指向的数组再向后偏移即*(*allStudents + i)。

    总而言之,赋值号=后面的求值结果与你从调试器看到不一致。
    raysonx
        32
    raysonx  
       2018-09-12 19:27:32 +08:00
    忽然发现我哦上面 *(allStudents + i)和*(*allStudents + i)的写法也是有歧义的。我也恨死 array to pointer decay 这个特性了。应当把 allStudents 替换 source.cpp 中那个全局指针变量的地址。
    innoink
        33
    innoink  
       2018-09-12 20:36:01 +08:00
    调试器没有链接步骤,是按照语法树来的,找到 allStudents 所在的编译单元,从它的语法树找到类型
    真正到了链接步骤,语法树已经没了
    kljsandjb
        34
    kljsandjb  
       2018-09-13 12:42:08 +08:00 via iPhone
    看到你贴的代码了,指针变量的值是你需要的,你这样 extern 的话,就是这个变量本身了。数组可以退化成指针,那这个指针指向的是数组首地址,但是指针转为数组的话,这个时候,你 focus 的地方应该是这个指针指向的内存位置,而不是这个指针本身在内存的位置。
    kljsandjb
        35
    kljsandjb  
       2018-09-13 12:55:01 +08:00 via iPhone   ❤️ 1
    举个例子,int arr[N];这是个数组定义,然后 int *p = arr, 这个时候 p 指向的是数组首地址。强行转为 p[]的话,那这个 p 你希望是转换之前 p 指向的位置的地址,这样就显然矛盾了:)
    bp0
        36
    bp0  
       2018-09-13 14:03:01 +08:00   ❤️ 2
    数组可以退化成指针,指针不能进化成数组。

    借用 @kljsandjb #35 的例子。
    数组的名称“ arr ”就是数组的第一个元素的地址,编译器并不会给“ arr ”额外分配一个地址。而指针“ p ”本身是要占用一个地址空间的,“ p ”的地址空间中保存的内容是数组“ arr ”的首地址。

    当编译器编译 TestStudent.cpp 文件时,会按照数组的方式直接使用“ allStudents ”的地址作为组数的首地址。而在编译 source.cpp 时,会给指针“ allStudents ”分配一个地址,并让其指向你动态分配的数组的首地址。

    所以 TestStudent.cpp 文件中实际上是把指针“ allStudents ”的地址当成数组的首地址使用了,自然得不到正确的内容。

    那为什么调试器能看到正确的内容呢?因为调试器是解析的 elf 文件中的 debug 信息。在 debug 信息中 allStudents 就是一个指针而不是一个数组。所以可以读到正确的内容。
    Deville
        37
    Deville  
       2018-09-13 17:55:47 +08:00
    @v2byy iOS 端图片显示了主题色- -。 看着感觉比较像。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1208 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 18:31 · PVG 02:31 · LAX 10:31 · JFK 13:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.