v2byy
V2EX  ›  C

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

  •  
  •   v2byy · Sep 11, 2018 · 5577 views
    This topic created in 2979 days ago, the information mentioned may be changed or developed.

    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;
    
    
    Supplement 1  ·  Sep 12, 2018

    不好意思,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是一个全局的变量。

    Supplement 2  ·  Sep 12, 2018

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

    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 replies  •  2018-09-13 17:55:47 +08:00
    Dori
    Dori
    Sep 11, 2018
    1
    踩踩
    coderluan
    coderluan
    Sep 11, 2018
    2
    ->
    raysonx
    raysonx
    Sep 11, 2018 via Android
    3
    代码看起来没有问题,不过我好奇的是 g_local_func 看起来是一个结构体变量,你是怎么应用下标的?
    kljsandjb
    kljsandjb
    Sep 11, 2018 via iPhone
    4
    上下文感觉不够啊…看不出来,还有 g_local_func 是个结构体数组?不一样至少说明 func_name 指向的内存被破坏了吧?看看栈有没有被破坏或者如果你是分配在堆上的话,是不是内存管理出了问题😂
    bp0
    bp0
    Sep 11, 2018
    5
    g_local_func 不是数组吧,怎么看都只是一个全局变量而已。去掉[i]试试看。
    si
    si
    Sep 11, 2018
    6
    猜不到是怎么赋值的
    inoki
    inoki
    Sep 11, 2018 via Android
    7
    lua interpreter 源代码?
    Deville
    Deville
    Sep 11, 2018 via iPhone
    8
    只能看得出是 vs 2017....
    zyp0921
    zyp0921
    Sep 12, 2018
    9
    这是 C 语言吧
    v2byy
    v2byy
    OP
    Sep 12, 2018
    10
    @raysonx 笔误,已 append
    v2byy
    v2byy
    OP
    Sep 12, 2018
    11
    @kljsandjb 恩,我是通过 malloc 来给 g_local_func 分配的内存,是这样的,我使用在 c 文件中声明并给 g_local_func 分配内存,然后在另外一个 c 文件中通过 extern 导入 g_local_func 变量,然后调用的这个方法。
    v2byy
    v2byy
    OP
    Sep 12, 2018
    12
    @bp0 笔误了,已 append
    v2byy
    v2byy
    OP
    Sep 12, 2018
    13
    @inoki 不是哦,export 一些函数给 lua 用而已。
    v2byy
    v2byy
    OP
    Sep 12, 2018
    14
    @Deville 怎么看出 vs2017 的?

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

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

    extern const int NUM;
    extern Student allStudents[];

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

    另外记得释放内存
    v2byy
    v2byy
    OP
    Sep 12, 2018
    23
    @innoink
    @kidtest

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

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

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

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

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

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

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

    那为什么调试器能看到正确的内容呢?因为调试器是解析的 elf 文件中的 debug 信息。在 debug 信息中 allStudents 就是一个指针而不是一个数组。所以可以读到正确的内容。
    Deville
    Deville
    Sep 13, 2018
    37
    @v2byy iOS 端图片显示了主题色- -。 看着感觉比较像。。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1722 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 67ms · UTC 14:39 · PVG 22:39 · LAX 06:39 · JFK 09:39
    ♥ Do have faith in what you're doing.