Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 链接结构的外部静态数组无法正常工作_C_Arrays_Struct_Extern_Static Array - Fatal编程技术网

C 链接结构的外部静态数组无法正常工作

C 链接结构的外部静态数组无法正常工作,c,arrays,struct,extern,static-array,C,Arrays,Struct,Extern,Static Array,我试图链接一个静态定义的结构数组。我正在使用extern修饰符来执行此操作。当我打印出extern结构的内存地址时,它与它在可执行文件中的位置不同 以下是我所拥有的: 类型.h: typedef struct tableEntry { const char *my_str; void *my_addr; int myint; } my_struct; include "type.h" my_struct my_array[] = { {"hello",

我试图链接一个静态定义的结构数组。我正在使用extern修饰符来执行此操作。当我打印出extern结构的内存地址时,它与它在可执行文件中的位置不同

以下是我所拥有的:

类型.h:

typedef struct tableEntry {
     const char *my_str;
     void *my_addr;
     int myint;
} my_struct;
include "type.h"

my_struct my_array[] = {
    {"hello", (void*)15, 5000},
    {"world", (void*)15, 3000},
    {"abtest", (void*)15, 2000},
};
#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);
}
test.c:

typedef struct tableEntry {
     const char *my_str;
     void *my_addr;
     int myint;
} my_struct;
include "type.h"

my_struct my_array[] = {
    {"hello", (void*)15, 5000},
    {"world", (void*)15, 3000},
    {"abtest", (void*)15, 2000},
};
#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);
}
main.c:

typedef struct tableEntry {
     const char *my_str;
     void *my_addr;
     int myint;
} my_struct;
include "type.h"

my_struct my_array[] = {
    {"hello", (void*)15, 5000},
    {"world", (void*)15, 3000},
    {"abtest", (void*)15, 2000},
};
#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);
}
当我运行我的可执行文件时,我得到以下输出:

array location - 0x4006be
array entry 1 myint - 29811
array entry 1 address - 0x6574626100646c72
array string location - 0x4006be
Segmentation fault (core dumped)
my_阵列的地址(以nm输出为单位):

0000000000601060 D my_array
如您所见,我的输出不是我期望的,并且我的_数组没有正确链接(nm输出中的位置与实际程序打印的位置不同)

注意:我不能在main.c中包含test.c文件。它必须链接。

更改

extern my_struct* my_array;


您不能使用
extern
将数组修改为指针。

my_数组的地址问题是您打印了指针包含的值。但是对于数组,您需要指针本身的地址(即数组第一个元素的地址)。然而,作为一个指针,它仍然被错误地声明(奇怪为什么编译器没有抱怨)

简称:

  • 结构x*p;//p是存储在x中的值:“它指向的位置”
  • 结构x q[];//q是第一个条目的地址(=数组的地址)
要获得p的相同值,实际上必须采用
&p
,但这将是指针指向指针的类型,而不是结构。这是数组和指针之间的区别之一。详细信息请阅读

因此,使用在
main.c
中的实现文件中使用的相同声明u。实际上,您应该将声明打包到标题
type.h
(注意这很容易与标准标题
type**s**.h
混淆)。在编译“type.c”时,这还会生成一个关于声明和定义不匹配的警告。实际上,这是头文件最重要的用途之一

对于实际地址和逻辑地址之间的差异
nm
报告:文件在执行之前加载到RAM,并且必须根据加载地址重新定位。文件中的地址实际上是相对于
.data
(初始化变量)或
.bss
(未初始化,默认为0变量)节的基址的,对于文件中的每个节,基址通常为0。加载时,RAM中的起始地址被添加到这些相对地址中,以获得实际地址。这就是为什么程序在加载后可能需要一些时间(重新定位可能相当复杂)的原因之一


有一个例外:如果您让链接器将程序重新定位到绝对地址,如裸机(没有完整的操作系统)嵌入式控制器,
nm
将报告与运行时或调试器中相同的地址。原因是链接器实际上包含上述运行时加载程序的作业。因此,代码必须加载到正确的地址范围,例如闪存。

这很容易。谢谢@你没有真正解决这个问题。请看奥拉夫的答案。@banach space:OP似乎认为是这样。@rost0031它确实修复了结果。可惜你不解释原因,是我解释的。OP似乎知道如何处理数组和指针。他只是不知道如何正确链接外部数组。几年前我遇到过同样的问题,我纠正了他代码中唯一的问题,并在最后一句中解释了原因。那么,请下一位投票者至少留下一条评论?
nm
,代码报告了与rost0031修复程序相似的地址。这使你的最后一段变得无关紧要。(顺便说一句,不是我投了反对票。)@banach-space:我没有怀疑你。对于
nm
:类似与“不同”im编程相同
nm
不能显示相同的地址,除非它适用于ld重新绑定到绝对地址的嵌入式系统。但这些信息并没有给出(既不是通过标签也不是显式的)。这是很公平的,但我尝试了代码并运行了
nm
,在这两种情况下我得到了相同的地址(在PC上,而不是在嵌入式平台上)。我对加载程序了解不多,但我怀疑由于VMA(假设我们生活在Linux世界中),在链接期间为
.data
计算的重新定位地址与执行期间的地址相同。这样,
nm
printf()
显示相同的地址。可以。但实际上,不同的
.bss
.data
大小和地址空间随机化会如何改变呢?另外,在统一的地址空间中如何工作?也许nm已经对符号进行了某种重新定位?无论如何,我实际上不会依赖于非绝对ELF部分。