LINUX.ORG.RU

типы в c

 ,


1

3

есть такая структурка:

struct x { int i; ... char buf[4096 - ???]; };

проблема в размере buf. должно быть так:

static_assert(sizeof(struct x) == 4096);

как написать там нужный размер без боли? очевидный вариант не проходит:

struct x { int i; ... char buf[4096 - offsetof(struct x, buf)]; }; // struct x is incomplete
struct x { struct { int i; ... } y; char buf[4096 - sizeof(y)]; }; // y is undeclared
struct x { struct y { int i; ... } y; char buf[4096 - sizeof(struct y)]; }; //это работает, но как и в предыдущем случае нужно будет писать x.y.i вместо x.i

лучшее, что придумал:

struct x { union { struct { int i; ... char buf[]; }; char _[4096]; }; };

но хочется иметь простой sizeof(buf), а не костылями. есть ли способ?



Последнее исправление: jsforever (всего исправлений: 2)
Ответ на: комментарий от u5er

не, такое я и без макрома могу сделать - просто посчитать/написать все размеры руками.

вот последний вариант в оп: там я дописываю ещё полей(после int i) и всё само пересчитывается. тут мне нужно будет не забыть ещё и размер вписать. да, можно просто поставить ассерт и оно еапомнит, но это некрасиво. лучше уж сайзоф чем-то заменить.

jsforever
() автор топика

Я бы предложил всë кроме buf объявить отдельной вспомогательной структурой и в основной структуре еë объявить первым полем, а уже вторым полем попробовать объявить buf с sizeof. По идее должно сработать.

unDEFER ★★★★★
()

Как только ты начал работать со структурами определенных размеров, то тут же нужно забыть про типы int/long int.

Вместо них нужно явно указывать размер типа int32_t/uint32_t. Тогда не будет боли при подсчёте.

vel ★★★★★
()

`struct x { union { struct { int i; … char buf[]; }; }; char _[4096];

Заполнитель _[4096] перемести внутрь union и всё будет работать.

#include <stdio.h>

struct x { 
  union { 
    struct { 
      int i; 
      char x; 
      float p; 
      long m; 
      char buf[64]; 
    };  
    char _[4096];
  }; 
};

int main(int argc, char *argv[])
{
    struct x y;
    y.i=12;
    y.x=13;
    y.p=0.4;
    y.buf[0]='l';
    y.buf[1]='o';
    y.buf[2]='\n';
    printf("%zu %d %d %f %s\n",sizeof(y),y.i,y.x,y.p,y.buf);
    return 0;
}
dron@gnu:~$ gcc cc.c
dron@gnu:~$ ./a.out 
4096 12 13 0.400000 lo

dron@gnu:~$ gcc -g3 -c cc.c
dron@gnu:~$ pahole cc.o 
struct x {
	union {
		struct {
			int        i;                    /*     0     4 */
			char       x;                    /*     4     1 */

			/* XXX 3 bytes hole, try to pack */

			float      p;                    /*     8     4 */

			/* XXX 4 bytes hole, try to pack */

			long int   m;                    /*    16     8 */
			char       buf[64];              /*    24    64 */
		};                                       /*     0    88 */
		char               _[4096];              /*     0  4096 */
	};                                               /*     0  4096 */

	/* size: 4096, cachelines: 64, members: 1 */
};
dron@gnu:~$ 
LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

bytes hole, try to pack

Именно поэтому, кстати, рекомендуют в структурах переменные располагать по размеру - большие в начале, а мелкие в конце.

/me Уже забыл всю сишку напрочь :(

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

А если на целевой платформе выравнивание float отличается от int? Да, на популярных платформах будет работать, но непортабельно.
Лучше всего не пытаться выставить размер массива.
Например

struct sbuffer_s
{
int i;
double d;
char buf[]
};
#define SBUFFER_SIZE 4096
#define SBUFFER_BUF_SIZE (4096 - offsetof(sbuffer_s,buf))

Потом выделять под него память соответственно макросу. Узнать размер хидера можно или через offsetof или вынеся его в отдельную вложенную структуру
Если надо аллоцировать как структуру, может попытаться сделать union:
union sbuffer_u
{
struct sbuffer_s s;
char data[4096]
};

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

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

Тогда задай типам фиксированные размеры stdint.h посчитай на калькуляторе их сумму и вычти из 4096 результатом будет размер buf и все юнионы и _ можно будет выкинуть, расположи данные так чтобы между ними не было дырок.

#include <stdio.h>
#include <stdint.h>

struct x
{
    uint32_t i;  //4
    uint32_t x;  //4
    float    p;  //4
    float    _unused_padding_;//4
    /*иное*/
    char buf[4096-4-4-4-4];
};

int main(int argc, char *argv[])
{
    struct x y;
    y.i=12;
    y.x=13;
    y.p=0.4;
    y.buf[0]='l';
    y.buf[1]='o';
    y.buf[2]='\n';
    printf("%zu %zu %d %d %f %s\n",sizeof(y),sizeof(y.buf),y.i,y.x,y.p,y.buf);
    return 0;
}
dron@gnu:~$ gcc cc.c 
dron@gnu:~$ ./a.out 
4096 4080 12 13 0.400000 lo

dron@gnu:~$ gcc -g3 -c cc.c
dron@gnu:~$ pahole cc.o 
struct x {
	uint32_t                   i;                    /*     0     4 */
	uint32_t                   x;                    /*     4     4 */
	float                      p;                    /*     8     4 */
	float                      _unused_padding_;     /*    12     4 */
	char                       buf[4080];            /*    16  4080 */

	/* size: 4096, cachelines: 64, members: 5 */
};
dron@gnu:~$ 

LINUX-ORG-RU ★★★★★
()

Завести копию структуры и мерить размер от неё

struct fake {
   int i;
   float f;
};

struct real {
   int i;
   float f;
   char buf[4096 - sizeof(struct fake)];
};

Можно через макрос:

#define S_DATA int i; float f; 

struct fake {
   S_DATA
};

struct real {
   S_DATA
   char buf[4096 - sizeof(struct fake)];
};
vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 1)
Ответ на: комментарий от mittorn

А если на целевой платформе выравнивание float отличается от int?

Да, мне выше уже напомнили про это. Я на сишке давно ничего не писал и уже успел её порядком подзабыть :(

будет ли так работать.

Будет. Если массив без размера стоит в конце структуры, то это допустимо. Таким образом можно любой кусок памяти должного размера привести к типу struct sbuffer_s (в данном случае) и работать с ним как с обычной структурой. Только нужно контролировать доступ в полю buf, чтоб не выйти за пределы.

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

Я имею в виду размер структуры так ли нужен 4096 если суть в том что нужно иметь некоторые поля и остальное отдать под буфер.

Типа если смысл в том что взял поле добавил, всё осталось как есть лишь буфер ужался. Ну в этом есть смысл, но глядя на перспективу получается будем иметь буфер который будет плавать в зависимости от наличия тех или иных полей. Что толку от гарантии размера структуры (читай куска памяти просто) в 4096 если у нас при наличии этой стабильности внутри нестабильный buf, а если смысл не в том чтобы вольно менять поля сохраняя размер структуры (для её записи куда то?) то вообще смысла нет.

Это всё странно, задай поля, дазай фиксированный размер буфера, а если ну вот надо обращаться к этому как к 4096 байтам блобу, то никто не мешает записать структуру в массив 4096 чаров, где то дальше в коде, где-то в 1 месте где это нужно :)

Хотя, ладно, автору виднее как там ему надо в его конкретном случае

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)

может в c++ есть возможность нормально такое написать? максимум на что меня хватило:

template<unsigned n> struct _x { int i; long l; float f; char buf[4096 - n]; };
using x = _x<offsetof(_x<0>, buf)>;
static_assert(sizeof(x) == 4096);

но это тоже так себе.

jsforever
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

будем иметь буфер который будет плавать в зависимости от наличия тех или иных полей

их там более ~100 байт не будет, поэтому тут всё нормально. да и размер буфера всё равно от балды выбирается, поэтому толку от того, что он будет постоянный. там +-100 байт роли не играют. в этот буфер всякие заголовки читаются(хттп в том числе).

Что толку от гарантии размера структуры (читай куска памяти просто) в 4096

чтобы ровно в страницу помещалось. таких структурок там потенциально много может быть, хочу покомпактнее.

jsforever
() автор топика
struct Foo
{
    uint32_t a;
    uint32_t b;
    uint32_t c;
    float f;
    double d;
};

template <typename T, size_t size>
struct AddBuffer : public T
{
    char tail[size - sizeof(T)];
};

using MyStruct = AddBuffer<Foo, 2048>;

static_assert(sizeof(MyStruct) == 2048);

int main()
{
    MyStruct s {0, 1, 2, 34.5f, 436.727, {}};
    std::cout << s.a << ", " << s.b;
}
Beewek ★★
()
Ответ на: комментарий от jsforever

Тогда уже никто без С ничего не может потому что ядро написано на C. А еще никто ничего не может без дяди Кости алкоголика, потому что именно дядя Костя открывает вентиль на ТЭЦ которая ток дает в розетку шоб все эти компуктеры работали.

На питоне же многие вещи (включая некоторые манипуляции по формированию памяти) могут быть гораздо проще чем на С, без всех этих плясок с бубном.

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

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

На питоне же многие вещи (включая некоторые манипуляции по формированию памяти) могут быть гораздо проще чем на С, без всех этих плясок с бубном.

можешь попробовать описать структурку из оп на питоне. опустим даже интерпретатор на си - пусть будет в качестве форы. вот нужно взять язык и на нём написать тип.

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

WTF «написать тип»? Это Вам питонофобия мешает нормально формулировать свои мысли, или у Вас всегда такие сложности?

Можно сделать питоновскую структуру которая умеет дампится в 4096 байт - это вообще без проблем. Только боюсь Вы не этого хотите, точнее судя по топику Вы сами не понимаете чего хотите, и питон с сями тут совершенно непричем.

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

buf будет ссылкой

Учите до просветления как устроены строки в плюсах. Внезапно - в Вашем примере buf тоже указатель, бгггг.

Я же говорю - у Вас большие проблемы с формулированием своих мыслей. Если бы Вы смогли сформулировать внятно что именно Вам требуется от того типа, то наверное Вам бы смогли помочь и в т.ч. питоновское решение предложить. А так простите, все телепаты в отпуске… остается над Вами только глумиться.

ЗЫ кстати в питоне есть нормальная интроспекция, поэтому автоматически что то упаковать и вычислить его размер там вообще одной строчкой делается. Но Вам же так хочется страдать фигней;-)

AntonI ★★★★★
()
Последнее исправление: AntonI (всего исправлений: 2)