Поскольку внутренний цикл обрабатывает данные с 16-битным шагом, addr
должен быть указателем на 16-битное значение, т. Е. uint16_t * addr
.
checksum
- любой тип данных, который вы хотитедля сохранения окончательного результата. Если вы вычисляете 16-битную контрольную сумму, она также будет uint16_t
.
. Обратите внимание, что sum
, вероятно, должно быть unsigned long
, а не long
.Это работает на практике, потому что сетевые пакеты, как правило, недостаточно велики, чтобы контрольная сумма переполняла long
(пакет должен быть не менее 32 Кбайт).Но если вы пишете код общего назначения, вам следует защищаться от кода.
Вы можете найти реализацию, которая использует подходящие переносимые типы данных:
http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html
uint16_t ip_checksum(void* vdata,size_t length) {
// Cast the data pointer to one that can be indexed.
char* data=(char*)vdata;
// Initialise the accumulator.
uint32_t acc=0xffff;
// Handle complete 16-bit blocks.
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Handle any partial block at the end of the data.
if (length&1) {
uint16_t word=0;
memcpy(&word,data+length-1,1);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Return the checksum in network byte order.
return htons(~acc);
}