Насколько стандарт C++ затронут, , ответ litb является абсолютно корректным и самым портативным. Кастинг const char *data
к const uint3_t *
, нарушает ли это быть через бросок C-стиля, static_cast
, или reinterpret_cast
, строгие правила искажения (см. Понимать Строгое Искажение ). Если Вы компилируете с полной оптимизацией, существует хороший шанс, код не будет к правильной вещи.
Кастинг через объединение (такое как litb's my_reint
) является, вероятно, лучшим решением, хотя это действительно технически нарушает правило, что, если Вы пишете в объединение через одного участника и читаете его через другого, это приводит к неопределенному поведению. Однако практически все компиляторы поддерживают это, и это приводит к ожидаемый результат. Если Вы абсолютно требуете соответствовать стандартным 100%, пойдите со смещающим бит методом. Иначе я рекомендовал бы идти с кастингом через объединение, которое, вероятно, даст Вам лучшую производительность.
Игнорирование эффективности, для простоты кода я сделал бы:
#include <numeric>
#include <vector>
#include <cstring>
uint32_t compute_checksum(const char *data, size_t size) {
std::vector<uint32_t> intdata(size/sizeof(uint32_t));
std::memcpy(&intdata[0], data, size);
return std::accumulate(intdata.begin(), intdata.end(), 0);
}
мне также нравится последний ответ litb, тот, который смещает каждый символ в свою очередь, за исключением того, что, так как символ мог бы быть подписан, я думаю, что этому нужна дополнительная маска:
checksum += ((data[i] && 0xFF) << shift[i % 4]);
, Когда трамбовка типа является потенциальной проблемой, я предпочитаю не вводить игру слов, а не пытаться сделать так безопасно. Если Вы не создаете искаженных указателей отличных типов во-первых, то Вы не должны волновать то, что компилятор мог бы сделать с псевдонимами, и ни один не делает программиста обслуживания, который видит Ваши несколько static_casts через объединение.
, Если Вы не хотите выделять так много дополнительной памяти, тогда:
uint32_t compute_checksum(const char *data, size_t size) {
uint32_t total = 0;
for (size_t i = 0; i < size; i += sizeof(uint32_t)) {
uint32_t thisone;
std::memcpy(&thisone, &data[i], sizeof(uint32_t));
total += thisone;
}
return total;
}
Достаточно оптимизации избавится от memcpy и дополнительной uint32_t переменной полностью на gcc, и просто считает невыровненное целочисленное значение, в том, что самый эффективный способ сделать, который находится на Вашей платформе, прямо из исходного массива. Я надеялся бы, что то же верно для других "серьезных" компиляторов. Но этот код теперь больше, чем litb's, таким образом, нет очень, чтобы быть сказанным для него кроме моего, легче превратиться в шаблон функции, который будет работать точно также с uint64_t и работами шахты как собственный порядок байтов вместо того, чтобы выбрать прямой порядок байтов.
Это, конечно, не абсолютно портативно. Это предполагает, что представление устройства хранения данных sizeof (uint32_t) символы соответствует представлению устройства хранения данных uin32_t в способе, которым мы хотим. Это подразумевается вопросом, так как он указывает, что можно "рассматриваться как" другой. Порядок байтов, является ли символ 8 битами, и использует ли uint32_t все биты в своем представлении устройства хранения данных, может, очевидно, нарушить, но вопрос подразумевает, что они не будут.
Это похоже на пример журнала того, когда использовать reinterpret_cast
, что-либо еще даст Вам тот же эффект без явности, которую Вы получаете от использования конструкции языка для ее служебного пользования.