Фактический общий размер членов структуры - PullRequest
3 голосов
/ 27 октября 2009

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

<code>
struct Data {
  char cmember;
  /* padding bytes */
  int  imember;  
};

AFAIK, большинство компиляторов добавят несколько байтов заполнения между членами cmember и imember членов Data, но я хочу сохранить в файл только актуальные данные (без отступов).
У меня есть следующий код для сохранения массива данных (в буфере вместо файла для упрощения):

<code>
bool saveData(Data* data, int dataLen, char* targetBuff, int buffLen)
{
  int actualLen = sizeof(char) + sizeof(int); // this code force us to know internal
                                              // representation of Data structure
  int actualTotalLen = dataLen * actualLen; 
  if(actualTotalLen > buffLen) {
    return false;
  }

  for(int i = 0; i &lt dataLen; i++) {
    memcpy(targetBuff, &data[i].cmember, sizeof(char));
    targetBuff += sizeof(char);
    memcpy(targetBuff, &data[i].imember, sizeof(int));
    targetBuff += sizeof(int);
  }
  return true;
}

Как видите, я вычисляю фактический размер структуры данных с помощью кода: int actualLen = sizeof(char) + sizeof(int). Есть ли альтернатива этому? (что-то вроде int actualLen = actualSizeof(Data))

P.S. это синтетический пример, но я думаю, вы понимаете идею моего вопроса ...

Ответы [ 12 ]

0 голосов
/ 27 октября 2009

Если вы можете переписать определение структуры, вы можете попытаться использовать спецификаторы полей, чтобы избавиться от дыр, например:

struct Data {  
   char cmember : 1;
   int  imember : 4;
};

К сожалению, это не гарантирует, что он все равно не поместит imember 4 байта после начала cmember. Но многие компиляторы поймут идею и сделают это в любом случае.

Другие альтернативы:

  1. Изменение порядка членов по размеру (сначала по величине). Это старый трюк со встроенным миром, чтобы минимизировать дыры.

  2. Вместо этого используйте Аду.

код

type Data is record
    cmember : character;
    imember : integer;
end record;

for Data use record
    cmember at 0 range 0..7;
    imemeber at 1 range 0..31;
end record;

делает именно то, что вы хотите.

0 голосов
/ 27 октября 2009

Нет, на самом языке нет способа получить эту информацию. Один из способов подойти к решению - косвенно определить классы данных, используя некоторую особенность языка - он может быть старомодным, как макросы и препроцессор, или таким же новым, как шаблоны кортежей. Вам нужно что-то, что позволяет систематически перебирать членов класса.

Вот подход, основанный на макросах:

#undef  Data_MEMBERS  
#define Data_MEMBERS(Data_OP) \  
    Data_OP(c, char) \  
    Data_OP(i, int)  
#undef  Data_CLASS_DEFINITION  
#define Data_CLASS_DEFINITION(name, type) \  
    type name##member;  
struct Data {  
    Data_MEMBERS(Data_CLASS_DEFINITION)  
};  
#define Data_SERIAL_SIZER(name, type) \  
    sizeof(type) +  
#define Data_Serial_Size \  
    (Data_MEMBERS(Data_SERIAL_SIZER) 0)

и пр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...