Mac上奇怪的C库链接问题-分段错误

时间:2019-03-27 18:29:19

标签: macos c segmentation-fault

我有一个奇怪的分段错误,当所有内容都在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

想知道为什么这样链接时会产生分段错误,以及我做错了什么。

我已经检查了otoolDYLD_PRINT_LIBRARIES=YES,并显示它正在导入动态链接的库,但是由于某种原因,它在链接时出现分段错误,而在未链接时可以正常工作。

1 个答案:

答案 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该对象是在其他地方定义的。