我有一个奇怪的分段错误,当所有内容都在1个.c文件中时,该错误就不存在,但是当我将部分代码放入动态链接库并将其链接到一个测试文件。可工作的1 .c文件代码的完整代码在底部,带有2 .c和1 .h文件的错误系统的完整代码位于最前面。
这是错误系统:
示例。h:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p);
示例。c:
#include "example.h"
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
example2.c :
这实际上是一个测试文件:
#include "example.h"
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here2");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("Start");
test_print();
puts("Done");
return 0;
}
制作文件:
我将example
链接到example2
,然后运行:
example:
@clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o example.dylib example.c
@clang example2.c example.dylib -o example2.o
@./example2.o
.PHONY: example
输出为:
$ make example
Start
Here1
Here 8
FOO
make: *** [example] Segmentation fault: 11
但是它应该显示以下内容的完整输出:
$ make example
Start
Here1
Here 8
FOO
BAR
Here2
Done
奇怪的是,如果使用此系统,一切都会正常运行
示例。c:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("ASF");
test_print();
return 0;
}
制作文件:
example:
@clang -o example example.c
@./example
.PHONY: example
想知道为什么这样链接时会产生分段错误,以及我做错了什么。
我已经检查了otool
和DYLD_PRINT_LIBRARIES=YES
,并显示它正在导入动态链接的库,但是由于某种原因,它在链接时出现分段错误,而在未链接时可以正常工作。
答案 0 :(得分:5)
您的问题是C:\Python27\include
中的问题:
example.h
由于MYARRAY *collection;
和main.c
都包含此文件,因此您最终两次定义了example.c
,这导致未定义的行为。您需要确保仅定义每个对象一次。详细信息相对来说并不重要,因为任何事情都可能发生未定义的行为,但是可能发生的情况是collection
正在为一个对象分配内存,而main.c
正在使用的对象仍然是example.c
。如评论中所述,由于您在NULL
中定义了collection
,因此链接程序可以构建可执行文件,而无需在动态库中查找该符号,因此不会出现链接时间警告关于它也被定义,并且显然在编译库时不会发出警告。
当您将所有内容放在一个文件中时,它为您工作,因为显然您不再需要定义两次。该错误本身与您正在使用动态库的事实无关,尽管这可能使检测起来更加困难。
最好在main.c
中定义它并提供一个构造函数,而example.c
无需能够直接访问它。但是,如果必须执行此操作,则在main()
中定义它,然后在头文件中声明一个example.c
标识符,以告诉extern
该对象是在其他地方定义的。