我有类似的问题,如 this question我的问题得到了类似于 this answer 的解决但我不明白是什么导致了这个问题。
我有三个结构File
, Line
和Buffer
在 app.h
中声明.
typedef struct File {
FILE *fs;
char *path;
size_t size;
} File;
typedef struct Line Line;
struct Line {
char *text;
size_t len;
size_t line_no;
Line *next;
Line *prev;
};
typedef struct Buffer {
int id;
File file;
Line *first;
Line *last;
Line *current;
int x_pos;
int y_pos;
int visual_x;
bool modified;
} Buffer;
Makefile
如下:
CC = gcc
CFLAGS = -Wall -Werror -g
LDFLAGS =
LDLIBS = -lcurses
OBJECTS = app.o io.o global.o move.o winio.o utils.o
all: app
app: $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@
%.o: %.c proto.h app.h
$(CC) $(CFLAGS) -c $<
.PHONY: clean
clean:
-rm app
-rm *.o
有一个全局指针 Buffer
结构:extern Buffer *buffer
在 proto.h
中声明并在 global.c
中定义和*buffer
动态分配在 io.c
。 io.c
中有几个函数与 *buffer
一起使用。我搬家了show_buffer()
io.c
的功能到另一个模块,如 winio.c
void show_buffer()
{
size_t i = 0, j = 0;
Line *it;
for (it = buffer->first; it != NULL && i < (LINES - STATBAR_HEIGHT);
it = it->next, i++) {
for (j = 0; it->text[j] != '\0'; j++) {
waddch(mainwin, it->text[j]);
}
}
}
我还删除了size
File
的成员结构。然后show_buffer()
在winio.c
不再工作了。我发现show_buffer()
正在处理损坏的 buffer->first
指针。我重新编译了每个模块,但没有用。
当我添加 size
时问题就解决了File
的成员再次结构。我还发现如果我移动 show_buffer()
返回io.c
,问题就解决了。我怀疑结构填充可能会导致问题。
我的问题是导致问题的原因以及如何避免它。
分辨率
预编译 header 导致问题,因为它没有被重新编译。
最佳答案
结构定义是编译时数据。编译源文件后,生成的二进制组件将采用的 struct
布局是固定的。如果您无法确保系统中与给定 struct 类型一起使用的所有组件都具有相同的该类型布局理念(如下所述),那么很容易导致数据损坏。您很幸运,在您的案例中,腐败很容易识别。
您的struct
定义应该(仅)出现在头文件中,并且依赖它的每个源文件都应该#include
该头文件。如果您通过添加或删除成员、更改成员的类型或重新排序成员来修改struct
的结构,则必须重新编译所有依赖 header 的源文件。 (任何半途而废的构建系统都将帮助您轻松实现这一目标。)
您可以通过使用指向 struct
类型的指针而不是使用 struct
本身来在某种程度上使自己免受此类问题的影响,但这仅在您需要取消引用指针。
关于c - 如何在 C 中声明结构以避免结构损坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28571641/