#c #return
Простите, вопрос уже задавали - я не нашел История: Пишу программу по работе с ДДП, АВЛ-деревом и хэш-таблицей. И есть такая структура: struct AVL { int value; unsigned char height; AVL *left, *right; }; В таком виде все работает Однако, если я меняю местами поля вот так: ` struct AVL { AVL *left, *right; int value; unsigned char height; }; Или использую #pragma pack: #pragma pack(push, 1) struct AVL { int value; unsigned char height; AVL *left, *right; }; #pragma pack(pop) То программа ломается. Я отследил в дебагере проблемное место, оно в функции создания АВЛ-дерева на основе ДДП: void bst_to_avl(BST *tree, AVL **root) { if (tree && root) { *root = avl_add(*root, tree->value); bst_to_avl(tree->left, root); bst_to_avl(tree->right, root); } } Вот состояние в проблемной функции до вызова avl_add: В функции avl_add создается правильная вершина: Но, после выхода из функции по return, оно портится и превращается в это: Естественно, дальше программа работает неправильно. И мне не понятно несколько вещей - как это исправить (если я из принципа хочу именно такой порядок полей) И из-за чего это вообще возникает? Возможно, где-то я допустил очень глупую ошибку и теперь просто не вижу её Если нужно, могу выложить сюда весь проект, но там много файлов Содержимое BST.h #ifndef _BST_H_ #define _BST_H_ typedef struct BST BST; struct BST { BST *left, *right; int value; }; BST *bst_add(BST *root, int num); void bst_free(BST *root); int count_peaks(BST *root); #endif Ссылка на исходники
Ответы
Ответ 1
Информация, предоставленная вам в комментариях (величина offsetof(AVL, right) отличается в разных единицах трансляции), говорит о том, что у вас разные единицы трансляции используют разные определения структуры struct AVL. Возможно, что "текст" этого определения используется один и тот же, но, например, установки выравнивания и/или упаковки данных - разные в разных единицах трансляции. Из этого вытекает и наблюдаемое вам поведение. Я попробовал ваш код - все прекрасно работает. Однако ваш makefile не строит полных зависимостей исходников от заголовочных файлов. То есть при изменении AVL.h автоматически перестраивается только AVL.c, но не остальные исходники, которые зависят от AVL.h. В этом, по-видимому, и заключается ваша проблема: вы меняете определение struct AVL, но потом под новое определение перестраиваете только AVL.c. При таком makefile вам обязательно нужно делать make clean после каждого изменения .h файла и перестраивать все заново с нуля. А в общем, в "настоящих" мейкфайлах обычно выполняется построение файлов зависимостей .d при помощи ключей компилятора группы -M. Такие .d файлы затем включаются в makefile. Именно благодаря им любые изменения в .h файлах приводят к перекомпиляции всех .c файлов, которые от них зависят. В вашем случае один из простейших вариантов решения проблемы: Добавить ключ -MMD в командную строку компилятора Включить .d файлы в makefile Удалять .d файлы в clean CC := gcc CFLAGS := -std=c99 -Wall -Werror DEPFLAGS := -MMD ifeq ($(mode), debug) CFLAGS += -g3 endif -include *.d %.o: %.c %.h $(CC) $(DEPFLAGS) $(CFLAGS) -c $< app.exe: main.o io.o BST.o AVL.o bst_to_avl.o arrgen.o hash_table.o search.o restruct.o $(CC) $^ -o $@ clean: rm *.o *.d *.exe Такой вариант подразумевает, что никто не будет удалять .d файлы отдельно от .o файлов.
Комментариев нет:
Отправить комментарий