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

2018-09-11 16:44:43 +08:00
 v2byy

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;

4421 次点击
所在节点    C
37 条回复
innoink
2018-09-12 16:35:57 +08:00
你把 extern Student allStudents[]改成 extern Students* allStudents
kidtest
2018-09-12 16:44:58 +08:00
file: TestStudent.cpp

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

extern const int NUM;
extern Student allStudents[];

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

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

多谢,但是为什么会出现这个问题呢?
innoink
2018-09-12 17:11:06 +08:00
@v2byy 类型不匹配。
innoink
2018-09-12 17:17:29 +08:00
@v2byy 链接过程是不做类型检查的,你想一下数组和指针变量的区别,指针额外占用一块内存保存地址,你把他声明为数组的话,连接器找到 allStudents 这个符号,会认为这就是数组首地址,即认为这个符号后面的数据就是数组内容。
innoink
2018-09-12 17:22:40 +08:00
或者你想一下,如果是真的有个 allStudents[],比如有个 Students allStudents[10],那么你 extern Students allStudents[],和你以前的写法之间的区别。
gnaggnoyil
2018-09-12 18:29:11 +08:00
您可能是 array to pointer decay 的受害者
raysonx
2018-09-12 18:37:23 +08:00
@innoink 但这并不能解释为何那条本地变量的的赋值结果会发生变化。我怀疑是因为调试器解析符号的行为和链接器实际链接的行为不一致,导致调试器里看到的=后面的值是错误的。
v2byy
2018-09-12 18:50:53 +08:00
@innoink 太感谢了
v2byy
2018-09-12 18:55:50 +08:00
@raysonx 是不是其实调试器显示的 allStudent[i].first-name 其实是错的,赋值操作其实是对的
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
2018-09-12 19:27:32 +08:00
忽然发现我哦上面 *(allStudents + i)和*(*allStudents + i)的写法也是有歧义的。我也恨死 array to pointer decay 这个特性了。应当把 allStudents 替换 source.cpp 中那个全局指针变量的地址。
innoink
2018-09-12 20:36:01 +08:00
调试器没有链接步骤,是按照语法树来的,找到 allStudents 所在的编译单元,从它的语法树找到类型
真正到了链接步骤,语法树已经没了
kljsandjb
2018-09-13 12:42:08 +08:00
看到你贴的代码了,指针变量的值是你需要的,你这样 extern 的话,就是这个变量本身了。数组可以退化成指针,那这个指针指向的是数组首地址,但是指针转为数组的话,这个时候,你 focus 的地方应该是这个指针指向的内存位置,而不是这个指针本身在内存的位置。
kljsandjb
2018-09-13 12:55:01 +08:00
举个例子,int arr[N];这是个数组定义,然后 int *p = arr, 这个时候 p 指向的是数组首地址。强行转为 p[]的话,那这个 p 你希望是转换之前 p 指向的位置的地址,这样就显然矛盾了:)
bp0
2018-09-13 14:03:01 +08:00
数组可以退化成指针,指针不能进化成数组。

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

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

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

那为什么调试器能看到正确的内容呢?因为调试器是解析的 elf 文件中的 debug 信息。在 debug 信息中 allStudents 就是一个指针而不是一个数组。所以可以读到正确的内容。
Deville
2018-09-13 17:55:47 +08:00
@v2byy iOS 端图片显示了主题色- -。 看着感觉比较像。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/488251

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX