我有以下结构:
typedef struct ann_t {
uint32_t xs;
uint32_t hs;
uint32_t ys;
float *x;
float *h;
float *y;
float **wxh;
float **why;
} ann_t;
通过以下方式初始化:
ann_t* ann_init(uint32_t xs, uint32_t hs, uint32_t ys) {
ann_t *ann = malloc(sizeof(ann_t));
ann->xs = xs;
ann->hs = hs;
ann->ys = ys;
ann->x = calloc(xs, sizeof(float));
ann->h = calloc(hs, sizeof(float));
ann->y = calloc(ys, sizeof(float));
ann->wxh = calloc(xs, sizeof(float*));
ann->why = calloc(hs+1, sizeof(float*));
int i, j;
for(i = 0; i < xs; i++) {
ann->wxh[i] = malloc(hs * sizeof(float));
}
for(i = 0; i < hs+1; i++) {
ann->why[i] = malloc(ys * sizeof(float));
}
// printf("%p\n", ann->x);
return ann;
}
将此代码包含在另一个程序中:
...
ann_t *ann = ann_init(25, 10, 4);
// printf("%p\n", ann->x);
ann->x[0] = 1.0;
...
结果是:
分段故障(核心已转储)
使用valgrind:
== 26436 ==使用大小为8的未初始化值
...
== 26436 ==
== 26436 ==大小为4的无效写入
...
== 26436 ==地址0x4c3a78000000000未堆栈,未分配或(最近)释放
我试图在一个较小的程序中重现它,但是没有。
更改结构以拥有uint64_t
而不是uint32_t
解决问题。
在ann->x
内部打印指针ann_init
我得到0x55601051f080和在外部0x1051f08000000000。
为什么会这样?
编辑:在其中一个文件中找到了罪魁祸首:
#pragma pack(1)
仍然不确定为什么这会导致问题。
如果我正在执行指针算术来访问struct字段,这是有道理的,但是我正在按名称访问struct字段,那么为什么它计算出错误的值?
为什么在init函数内部没问题,但在外部访问失败?
从对问题的评论中得出的答案...
假设您在标头中定义了一个更简单的结构:
// header.h
typedef struct {
char foo;
int *ptr;
} fish_t;
和两个源文件:
// src1.c
#include "header.h"
int dummy_int = 5;
fish_t my_fish;
my_fish.foo = 'a';
my_fish.ptr = &dummy_int;
use_fish_fn( &my_fish );
// src2.c
#pragma pack(1)
#include "header.h"
void use_fish_fn( fish_t *f )
{
int bar = *f->ptr;
}
第一个文件(不带包装)可能看起来fish_t
像是这样的内存布局:
0: | foo | pad | pad | pad | // one byte char, three bytes padding
4: | ptr | // four byte pointer
但是第二个文件(带有包装)如下所示:
0: | foo | ptr ... | // one byte char, 3/4 of pointer
4: |...ptr | // last part of pointer
因此,当第二个文件尝试读取(然后取消引用)指针时,它实际上是在读取填充中碰巧的所有内容,这肯定会出错。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句