Пока писал учебную ОС, пришлось в качестве одной из функций стандартной библиотеки написать функцию 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]
Комментариев нет:
Отправить комментарий