Страницы

Поиск по вопросам

вторник, 4 июня 2019 г.

Функция memset_word делает пропуск между словами

Пока писал учебную ОС, пришлось в качестве одной из функций стандартной библиотеки написать функцию memset_word. Проблема была тут же решена "в лоб":
void memset_word(uint16_t* mem, uint16_t value, size_t count) { uint16_t* addr; for(addr = mem; addr < mem + count * sizeof(uint16_t); addr += sizeof(uint16_t)) { *addr = value; } }
Но у этой функции было обнаружено неприятное свойство: она записывает слова через одно. Другими словами, память была такая:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
а после вызова
memset((uint16_t*) 0, 0xCDAB, 3)
стала такая:
AB CD 00 00 AB CD 00 00 AB CD 00 00 00 00 00 00 00 00 00 00
хотя должна была стать такой:
AB CD AB CD AB CD 00 00 00 00 00 00 00 00 00 00 00 00 00 00
В принципе, помогает замена addr += sizeof(uint16_t) на addr++, но я не понимаю: ведь указатели в C - настоящие адреса, так почему же для того, чтобы перейти к следующему слову, нужно прибавлять 1, а не размер слова? Или же ошибка кроется где-то в коде функции? Прошу объяснить мне это.


Ответ

У вас эта функция
void memset_word(uint16_t* mem, uint16_t value, size_t count) { uint16_t* addr; for(addr = mem; addr < mem + count * sizeof(uint16_t); addr += sizeof(uint16_t)) { *addr = value; } }
некорректная. В ней неправильно используется арифметика указателей.
Я думаю, вы имели в виду следующее
void memset_word(uint16_t* mem, uint16_t value, size_t count) { for(uint16_t *addr = mem; addr != mem + count; ++addr ) *addr = value; } }
Вы должны перейти к следующему объекту. Увеличение указателя на 1 увеличивает его адрес на sizeof( uint16_t )
В этом состоит принцип работы оператора индексирования, когда вы пишите, например,
mem[1]
что эквивалентно выражению *(mem + 1) и в виду коммутативности операции сложения вы можете также записать
1[mem]

Комментариев нет:

Отправить комментарий