链接外部静态结构数组无法正常工作
Linking an extern static array of structs is not working correctly
我正在尝试 link 一个静态定义的结构数组。我正在使用 extern 修饰符来这样做。当我打印出 extern 结构的内存地址时,它与它在可执行文件中的位置不同。
这是我的:
type.h:
typedef struct tableEntry {
const char *my_str;
void *my_addr;
int myint;
} my_struct;
test.c:
include "type.h"
my_struct my_array[] = {
{"hello", (void*)15, 5000},
{"world", (void*)15, 3000},
{"abtest", (void*)15, 2000},
};
main.c:
#include <stdio.h>
#include "type.h"
extern my_struct* my_array;
int main() {
printf("array location - %p\n", my_array);
printf("array entry 1 myint - %d\n", my_array[0].myint);
printf("array entry 1 address - %p\n", my_array[0].my_addr);
printf("array string location - %p\n", &(my_array[0].my_str));
printf("array string - %s\n", my_array[0].my_str);
}
我是这样编译程序的:
gcc test.c main.c
当我 运行 我的可执行文件时,我得到以下输出:
array location - 0x4006be
array entry 1 myint - 29811
array entry 1 address - 0x6574626100646c72
array string location - 0x4006be
Segmentation fault (core dumped)
my_array 在 nm 输出中的地址:
0000000000601060 D my_array
如您所见,我的输出不是我所期望的,并且 my_array 没有正确 linked(nm 输出中的位置与实际程序打印的位置不同) .
注意:我不能在我的 main.c 中包含 test.c 文件。必须 linked.
改变
extern my_struct* my_array;
到
extern my_struct my_array[];
您不能使用 extern
将数组修改为指针。
my_array 地址的问题是您打印 值 指针 包含 。但是对于数组,您需要指针本身的地址(这将是数组第一个元素的地址)。然而,作为一个指针,它仍然被错误地声明(想知道为什么编译器没有抱怨)。
短:
- 结构x *p; // p 是存储在 x 中的值:"where it points to"
- 结构xq[]; // q 是第一个条目的地址(== 数组的地址)。
要获得相同的 p,您实际上必须采用 &p
,但那将是指向指针的指针类型,而不是结构。这是数组和指针的区别之一。阅读 standard 了解详情。
因此,使用您在 main.c
中的实现文件中使用的相同声明。实际上,您应该将声明打包到 header type.h
中(注意这很容易与标准的 header type**s**.h
混淆)。当您编译“type.c”时,它还会生成有关声明和定义不匹配的警告。这实际上是 header 最重要的用途之一。
对于实际地址与逻辑地址之间的差异nm
报告:文件加载到RAM之前执行并且必须根据加载地址重定位。文件中的地址实际上是相对于 .data
(已初始化变量)或 .bss
(未初始化,默认为 0 个变量)部分的基地址而言的,通常文件中的每个部分都是 0。加载时,将RAM中的起始地址与这些相对地址相加得到实际地址。这是程序加载后可能需要一些时间的原因之一(重定位可能非常复杂)。
有一个例外:如果您让链接器将程序重定位到绝对地址,例如 bare-metal(没有 full-grown OS)嵌入式控制器,nm
应报告与 run-time 期间或调试器中相同的地址。原因是链接器实际上包含了上述 run-time 加载器的工作。因此,代码必须加载到正确的地址范围,例如到闪存。
我正在尝试 link 一个静态定义的结构数组。我正在使用 extern 修饰符来这样做。当我打印出 extern 结构的内存地址时,它与它在可执行文件中的位置不同。
这是我的:
type.h:
typedef struct tableEntry {
const char *my_str;
void *my_addr;
int myint;
} my_struct;
test.c:
include "type.h"
my_struct my_array[] = {
{"hello", (void*)15, 5000},
{"world", (void*)15, 3000},
{"abtest", (void*)15, 2000},
};
main.c:
#include <stdio.h>
#include "type.h"
extern my_struct* my_array;
int main() {
printf("array location - %p\n", my_array);
printf("array entry 1 myint - %d\n", my_array[0].myint);
printf("array entry 1 address - %p\n", my_array[0].my_addr);
printf("array string location - %p\n", &(my_array[0].my_str));
printf("array string - %s\n", my_array[0].my_str);
}
我是这样编译程序的:
gcc test.c main.c
当我 运行 我的可执行文件时,我得到以下输出:
array location - 0x4006be
array entry 1 myint - 29811
array entry 1 address - 0x6574626100646c72
array string location - 0x4006be
Segmentation fault (core dumped)
my_array 在 nm 输出中的地址:
0000000000601060 D my_array
如您所见,我的输出不是我所期望的,并且 my_array 没有正确 linked(nm 输出中的位置与实际程序打印的位置不同) .
注意:我不能在我的 main.c 中包含 test.c 文件。必须 linked.
改变
extern my_struct* my_array;
到
extern my_struct my_array[];
您不能使用 extern
将数组修改为指针。
my_array 地址的问题是您打印 值 指针 包含 。但是对于数组,您需要指针本身的地址(这将是数组第一个元素的地址)。然而,作为一个指针,它仍然被错误地声明(想知道为什么编译器没有抱怨)。
短:
- 结构x *p; // p 是存储在 x 中的值:"where it points to"
- 结构xq[]; // q 是第一个条目的地址(== 数组的地址)。
要获得相同的 p,您实际上必须采用 &p
,但那将是指向指针的指针类型,而不是结构。这是数组和指针的区别之一。阅读 standard 了解详情。
因此,使用您在 main.c
中的实现文件中使用的相同声明。实际上,您应该将声明打包到 header type.h
中(注意这很容易与标准的 header type**s**.h
混淆)。当您编译“type.c”时,它还会生成有关声明和定义不匹配的警告。这实际上是 header 最重要的用途之一。
对于实际地址与逻辑地址之间的差异nm
报告:文件加载到RAM之前执行并且必须根据加载地址重定位。文件中的地址实际上是相对于 .data
(已初始化变量)或 .bss
(未初始化,默认为 0 个变量)部分的基地址而言的,通常文件中的每个部分都是 0。加载时,将RAM中的起始地址与这些相对地址相加得到实际地址。这是程序加载后可能需要一些时间的原因之一(重定位可能非常复杂)。
有一个例外:如果您让链接器将程序重定位到绝对地址,例如 bare-metal(没有 full-grown OS)嵌入式控制器,nm
应报告与 run-time 期间或调试器中相同的地址。原因是链接器实际上包含了上述 run-time 加载器的工作。因此,代码必须加载到正确的地址范围,例如到闪存。