@nymitr

Есть ли способ посчитать хэшсумму объявления структуры?

Есть структура в которой критичны типы, порядок и имена полей. Необходимо узнавать, когда программист изменил эту структуру.
В данный момент используется дополнительное добавленное поле структуры (int magicNumber), значение которой программист изменивший структуру меняет на отличное от указанного предыдущим.
Понятное дело что такой подход череват ошибками, когда magicNumber забывается измениться, либо случайно меняется на используемый ранее.
Возникла идея считать хеш-сумму объявления структуры.
Какие есть возможные способы?
UPD:1)Важность порядка необходима из-за того что эта структура хранит в себе параметры работы устройсва, калибровки и прочие важные вещи изаписывается в устройсво.
2) Вариант с гитом не совсем подходит т.к. отображает изменение всего файла, а не только структуры.
  • Вопрос задан
  • 2381 просмотр
Пригласить эксперта
Ответы на вопрос 5
@MarkusD
все время мелю чепуху :)
Если я правильно понял суть вопроса, то могу предложить один вариант. Скажем, будем считать CRC32 на этапе компиляции (тема бородатая, делается легко). Предположим, что 11 стандарта на руках нету.
В первую очередь надо взять строку от определения структуры. Сделать это можно так:

#define TOSTR( V )  #V
#define MKSTR( V ) TOSTR( V )
#define STRINGIFY_BODY( STR_NAME, ... ) \
static const char* STR_NAME = MKSTR( __VA_ARGS__ ); \
__VA_ARGS__

STRINGIFY_BODY( MY_STRUCT_STR,
struct MyStruct {
	uint32_t	m_field1;
	int16_t	m_field2;
	int64_t	m_field3;
}
);


Конечно-же, сама строка нам тут не нужна, а нужна именно CRC32. Да при том, посчитанная в compile-time.
Для этого вводим в свой код такой вот ужас:
static const uint32_t CRC32_TABLE[256] = {
... // тут много констант.
};

template< int pos >
__forceinline uint32_t make_crc32( const char* data ){
	const uint32_t crc = make_crc32< pos - 1 >( data );
	return ( crc >> 8 ) ^ CRC32_TABLE[ ( crc ^ data[ pos ] ) & 0x000000FFU ];
};

template<>
__forceinline uint32_t make_crc32<-1>( const char* data ){
	return 0xFFFFFFFFU;
};

// -1 будет указывать на концевой ноль строки,
// а -2 - в самую пору для начала подсчета - это последний символ строки.
#define GET_CRC32( V ) ( make_crc32< sizeof( V ) - 2 >( V ) ^ 0xFFFFFFFFU )


В самом подсчете суммы я мог наломать дров, точностей на скорую руку не помню. Поправьте меня, если не так.
Что это за код.
"__forceinline" - специальное слово для MSVC++ компилятора, указывающее принудительное развертывание этого кода. Работает это слово только при включенной оптимизации.
Шаблон "make_crc32" будет инстанцирован столько раз, какая в коде встретится максимальная длина строки. В релизе шаблоны "make_crc32" будут схлопнуты в значения, а табличка "CRC32_TABLE" будет вырезана из бинарника за ненадобностью. Контрольная сумма посчитатся при сборке проекта.
Теперь осталось только дописать макрос стрингификатор.

#define STRINGIFY_BODY( CRC_NAME, ... ) \
static const uint32_t CRC_NAME = GET_CRC32( MKSTR( __VA_ARGS__ ) ); \
__VA_ARGS__


А использовать теперь этот стрингификатор можно вот так:

STRINGIFY_BODY( MY_STRUCT_CRC,
struct MyStruct {
	static const uint32_t H;

	uint32_t	m_field1;
	int16_t	m_field2;
	int64_t	m_field3;
}
);

const uint32_t MyStruct::H = MY_STRUCT_CRC;


...или как-либо иначе. Идея, в общем, нарисовалась вот такая.
От __forceinline можно избавиться в пользу constexpr (для случая с 11 стандартом), результат должен быть таким же.
В релизе breakpoint внутри подсчета CRC32 не сработает, т.к. все уже посчитано, а в дебаге будет работать (если в дебаге оптимизация не включена).
Ответ написан
Комментировать
@DancingOnWater
откройте для себя git
Ответ написан
Комментировать
@nymitr Автор вопроса
гитом я пользуюсь и вопрос не об этом.
если у меня одна структура была записана в пямять устройства, а потом программист изменивший ее не изменит magicNumber, то программа никак не узнает что данные не валидные.
Ответ написан
maaGames
@maaGames
Погроммирую программы
Про git/svn/"любимая система управления версиями" хороший совет дали.
С их же помощью можно сделать автоматизацию назначения этого magicNumber'a. Достаточно присвоить ему номер ревизии для файла со структурой. Добавить в скрипт, который делает коммиты функцию, в которой корректировать значение этого магического числа в соответствии с номером следующей ревизии.
Хотя вообще попахивает не очень хорошей архитектурой и эмуляцией полиморфизма на Сишке (на такие мысли натолкнула важность порядка полей).
Ответ написан
@vilgeforce
Раздолбай и программист
#pragma pack вам же тоже важен? Если да - хэш не спасет.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы