Итак, я пытаюсь реализовать свой личный MemSet
, который будет делать то же самое, что и memset
, но также:
По возможности копируйте фрагменты размером слова, а не байт за байтом.
Гарантия выравнивания назначения
Проверка всех возможностей выравнивания
Итак, это мой код:
void *MemSet(void *dest, int c, size_t n)
{
unsigned char *runner = (unsigned char *)dest;
size_t i = 0;
unsigned char swap_word[sizeof(size_t)];
for (i = 0; i < sizeof(size_t); ++i)
{
swap_word[i] = (unsigned char)c;
}
if (NULL == dest)
{
return (NULL);
}
while (n > 0)
{
/* setting byte by byte */
if (n < sizeof(size_t) || (((size_t)runner & (sizeof(size_t) - 1)) != 0))
{
*runner++ = (unsigned char)c;
--n;
printf("Byte written\n"); /* for debugging */
}
else
{
/* setting a whole word */
*((void **)runner) = *((void **)swap_word);
runner += sizeof(size_t);
n -= sizeof(size_t);
printf("Word written\n"); /* for debugging */
}
}
return (dest);
}
Что я здесь делаю?
создание указателя без знака
runner
для запуска поверхdest
, но без изменения его адреса, поэтому я смогу вернуть его в качестве возвращаемого значения.создание готового массива
swap_word
с размеромsizeof(size_t)
, потому что этот размер определяет, является ли моя машина 32-битной или 64-битной (и, следовательно, размерWORD
составляет 4 или 8 байтов. Этот массив будет заменен, когда мне нужно будет установить слово.запуск простого
while loop
, который проверит, осталось ли для установки болееsizeof(size_t)
байтов, если нет, это точно означает, что мы не сможем установить целое слово, а затем установить их байт за байтом.Другой вариант установить байты побайтно, если адрес не делится на 4 или 8 (опять же, зависит от машины), что означает, что я не смогу установить слово без пересечения
WORD Boundary
, поэтому просто установите их байт за байтом, пока я не достигну выровненного адреса.Единственный вариант настроить целое слово — только если данные уже выровнены с
WORD size
машины, а затем просто установить 8 байт (просто установите их, используя массивswap_word
, который мы сделали ранее, и продвиньте еще 8 адресов. Я сделаю это с помощью приведения*((void **)бегун) = *((void **)swap_word);
и это мой тестовый файл:
int array[] = { 2, 3 };
int main ()
{
for (i = 0; i < 2; i++)
{
printf("Before MemSet, target is \"%d\"\n\n", array[i]);
}
if (NULL == MemSet(array, 3, 2 * sizeof(int)))
{
fprintf(stderr,"MemSet failed!\n");
}
for (i = 0; i < 2; i++)
{
printf("After MemSet, target is \"%d\"\n\n", array[i]);
}
return (0);
}
Выход:
Before Memset, target is "2"
Before Memset, target is "3"
Word written
After Memset, target is "50529027"
After Memset, target is "50529027"
Почему элементы не «3»? оба из них? я использую здесь
MemSet(array, 3, 2 * sizeof(int))
Что, по идее, должно установить оба элемента как 3
, потому что массив использует 2*sizeof(int)
пробелов в памяти, а я устанавливаю их все как 3
.
Как вы думаете? А также, как я могу проверить, работает ли мое выравнивание?
Спасибо.
(uintptr_t)0x0101010101010101
-->UINTPTR_MAX/0xFF
. Теперь не ограничиваетсяsizeof(uintptr_t) <= 8
. 09.03.2021while ((uintptr_t)p & (sizeof(uintptr_t) - 1))
— разумный, но не указанный способ достижения выравнивания. Нет способа сделать это в C. 09.03.2021while ((uintptr_t)p & (alignof(uintptr_t) - 1))
, но это было бы менее портативно. 09.03.20214
, но, возможно, я использую#define CHUNK 4
или что-то подобное. 09.03.2021(uintptr_t)p & anything
предполагает математическое свойство преобразованного указателя - значения указателя не указаны как линейные, но, скорее всего, таковыми являются. Хорошая работа МАК. 09.03.2021uintptr_t
, поэтому я используюsize_t
09.03.2021size_t
. Он компилируется и запускается, но относительно отправкиstrings
в функцию - не работает. Что касается int, он работает, в приведенном выше примере, отправляющемint array
из 2 элементов, он устанавливает число24
для первых элементов, а 2-й -0
. Вместо того, чтобы они оба были3
09.03.202150529027
, которое вы наблюдаете. Должна быть другая проблема при копировании приведенного выше кода, чтобы получить результат в комментарии. В частности, что вы имеете в виду под относительно строк, отправляемых в функцию - это не работает? 09.03.2021uintptr_t
наsize_t
, вы также должны изменитьUINTPTR_MAX
наSIZE_MAX
. 09.03.2021int value
теперь я понимаю, что мой код также работает по мере необходимости). Вы сделали 3 петли, которые делают то же самое, что и моя одна петля (на мой взгляд) 09.03.2021swap_word
, но он будет работать для текущих процессоров Intel. Мое предложение уменьшает количество тестов для больших размеров примерно до 0,25 на слово и пропускает накладные расходы для небольших размеров... Это больше работы, но в среднем может быть более эффективным, в зависимости от конкретного использования приложения. 09.03.2021while ((uintptr_t)p & (sizeof(uintptr_t) - 1))
действителен и определяет, соответствует ли адрес 4/8 (в зависимости от машины)? Почему здесь требуется-1
? 09.03.2021sizeof(uintptr_t)-1
— это битовая маска, в которой все биты установлены ниже значения выравнивания.while ((uintptr_t)p & mask)
эквивалентноwhile (((uintptr_t)p & mask) != 0)
проверяет, является ли указатель невыровненным, т.е. установлен ли один из младших битов. 09.03.2021