#macos #c #segmentation-fault
#macos #c #ошибка сегментации
Вопрос:
У меня странная ошибка сегментации, которая не существует, когда все находится в файле 1 .c, но существует, когда я помещаю часть кода в динамически связанную библиотеку и связываю ее с тестовым файлом. Полный код для рабочего кода файла 1 .c находится внизу, полный код для системы ошибок с файлами 2 .c и 1 .h идет первым.
Вот система ошибок:
example.h:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p);
example.c:
#include "example.h"
void
mypush(void* p) {
printf("Here %lun", sizeof collection);
puts("FOO");
int len = collection->len ;
puts("BAR");
collection->items[len] = p;
}
пример2.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;
}
Makefile:
Я ссылаюсь 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
Странно то, что все работает, если это эта система:
example.c:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p) {
printf("Here %lun", 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;
}
Makefile:
example:
@clang -o example example.c
@./example
.PHONY: example
Интересно, почему это создает ошибку сегментации, когда она связана подобным образом, и что я делаю неправильно.
Я проверил otool
и с DYLD_PRINT_LIBRARIES=YES
помощью, и это показывает, что импортируются динамически связанные библиотеки, но по какой-то причине ошибка сегментации при подключении, но работает нормально, когда она не связана.
Ответ №1:
Ваша проблема заключается в example.h
:
MYARRAY *collection;
Поскольку оба main.c
и example.c
включают этот файл, вы в конечном итоге определяете collection
дважды, что приводит к неопределенному поведению. Вам нужно убедиться, что вы определяете каждый объект только один раз. Детали относительно неважны, поскольку с неопределенным поведением может произойти что угодно, но, вероятно, происходит то, что main.c
выделяется память для одного объекта, но тот, который example.c
используется, все еще NULL
используется. Как упоминалось в комментариях, поскольку вы определяете collection
в main.c
, ваш компоновщик может создавать исполняемый файл без необходимости искать этот символ в динамической библиотеке, поэтому вы не получаете предупреждение о времени привязки о том, что он также определен там, и, очевидно, не было бы причин для предупреждения во время компиляции библиотеки.
Это работает для вас, когда вы помещаете все в один файл, потому что, очевидно, тогда вы больше ничего не определяете дважды. Сама ошибка не имеет ничего общего с тем фактом, что вы используете динамическую библиотеку, хотя это, возможно, затруднило ее обнаружение.
Было бы лучше определить это в example.c
и предоставить функцию конструктора, main()
нет необходимости иметь к ней прямой доступ. Но если вы должны это сделать, то определите это в example.c
и просто объявите extern
идентификатор в файле заголовка, чтобы сообщить main.c
, что объект определен где-то еще.
Комментарии:
1. В дополнение к вашему объяснению, нет предупреждения о времени привязки, поскольку
collection
оно определено как в исполняемом файле, так и в динамически связанной библиотеке… определенно 2 отдельных объекта2. @chqrlie: Хорошее дополнение, добавлено к ответу.
3. Я попробовал macOS X, у меня была та же ошибка сегментации. Имея только объявление коллекции в файле заголовка и объявив его в exemple.c , выполнение нормально. Конечно, за голосование ^^