LINUX.ORG.RU

Выравнивание неполного типа, расположенного на стеке

 , ,


1

3

Доброго дня.
Меня интересует, как можно разместить opaque type на стеке, использовав его нативное выравнивание. Пока у меня есть такое:

/* foo.h */

#ifndef FOO_H
#define FOO_H
	
#include <stddef.h>
#include <stdalign.h>

typedef struct foo Foo;
typedef unsigned char foo_store;

extern const size_t foo_sz;
extern const size_t foo_align;

Foo* foo_init (void);
Foo* foo_init_local (foo_store *store);

#define foo_local(x) alignas(max_align_t) foo_store x[foo_sz]

#endif //FOO_H
/* foo.c */

#include <stdlib.h>
#include "foo.h"

struct foo {
	int a;
	float b;
	double c;
	void *ptr;
};

const size_t foo_sz = sizeof(struct foo);
const size_t foo_align = alignof(struct foo);

inline static void assign (struct foo *f);

struct foo* foo_init (void) {
	Foo *f = malloc(sizeof *f);
	assign(f);
	
	return f;
};

struct foo* foo_init_local (foo_store *store) {
	struct foo *f;
	if (!store)
		return NULL;
		
	f = (struct foo*)store;
	assign(f);
	
	return f;
};

inline static void assign (struct foo *f) {
	f->a = 1;
	f->b = 2.0;
	f->c = 3.0;
	f->ptr = (void*)0xB16B00B5;
}

/* main.c */

#include <stdalign.h>
#include "foo.h"

int main (void) {
	foo_local(store);
	Foo *f = foo_init_local(store);
	
	return 0;
}

Всё вроде как работает нормально, но используется выравнивание по границе 16, а не 8. Условие: нельзя тупо задефайнить FOO_ALIGN 8 в foo.h (ну типа вдруг я захочу изменить состав struct foo). Я почему спрашиваю-то вообще. Вот говорят, что плохо выделять маленькие структуры в куче из-за её фрагментации (вопрос производительности не рассматриваем). Не возникнет ли некоего подобия фрагментации на стеке из-за несоответствующего выравнивания? Ведь адресов, кратных 16 в два раза меньше, чем кратных 8 (да ведь?). Ну и заодно: как malloc() выравнивет память? Надеюсь, понятно объяснил. Мне это ни для чего не надо, спрашиваю из интереса.

На первые вопросы не отвечу, но malloc скажу: никак он память не выравнивает, ибо не обязан. Ради аллокации с выравниванием можешь почитать man posix_memalign.

Олсо, судя по твоим вопросам, ты плохо понимаешь происходящее. Что есть, по-твоему, фрагментация и чем она плоха в куче?

devsdc ★★ ()
Ответ на: комментарий от devsdc

Что есть, по-твоему, фрагментация

Отсутствие больших непрерывных кусков памяти.

чем она плоха в куче

Тем, что невозможно будет выделить нужный размер, так как не будет непрерывного блока этого размера.

PamidoR ()
Ответ на: комментарий от PamidoR

Ну окей. На стеке ничего похожего на фрагментацию быть не может, потому что свободное место ищется не среди какого-то рандомного набора свободной памяти, а в строго определённом месте: после последнего занятого куска, стек же. Память там может кончиться только в случае с stack overflow.

devsdc ★★ ()
Ответ на: комментарий от devsdc

Понятно. То есть решение с alignas(max_align_t) foo_store x[foo_sz] нормальное и можно не париться?

PamidoR ()
Ответ на: комментарий от devsdc

фрагментация и чем она плоха в куче?

Тем что странички подгружаться чаще будут разные, в особо тяжких случаях ещё и из свопа :)

pon4ik ★★★★★ ()
Ответ на: комментарий от gh0stwizard

Предварительная оптимизация - худший баг.

И что же стоит за этим утверждением, кроме бла-бла? И какое же отношение ты имеешь к оптимизации, чтобы о ней балаболить, либо хотябы даже упоминать о ней?

Ты производил замеры?

Замеры чего? Ты их производил?

vmstat в руки.

И чего же vmstat, что мне с ним делать?

TrueTsarC ()
Ответ на: комментарий от TrueTsarC

Спокойно. Забыл, что в линуксе vmstat не такой крутой как в солярисе. Вместо этого можно посмотреть в top (зависит от версии).

gh0stwizard ★★★★★ ()
Ответ на: комментарий от gh0stwizard

Я не говорю что в этом случае не насрать, я просто рассказал челу, чем чревато в принципе, на случай, если он искрене полюбопытствовал.

pon4ik ★★★★★ ()

gcc выравнивает стек на 16 после входа в функцию но до выделения локальных переменных

если ты будешь работать с SSE, тебе надо на 16 иначе хватит на 8. НО иногда надо на 64 выравниваться если переменная из стека уйдёт куда-то по указателю в высоконагруженную часть потому что иначе ты будешь получать лишние кэшпромахи

ckotinko ☆☆☆ ()
Ответ на: комментарий от ckotinko

и вот еще что. попробуй obstack это как стэк только не стэк. их можно завести много. есть в gnu libc

как уже говорили, если будешь дрючить структуру часто, то на 64, если очень часто и вперемешку с другими - на 512 или 4096(это уже по контроллеру памяти выравнивание)

ckotinko ☆☆☆ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.