Пример:
// Copies count bytes from src to dst. The source and destination
// blocks are permitted to overlap.
public static void Copy(void* src, void* dst, int count)
{
byte* ps = (byte*)src;
byte* pd = (byte*)dst;
if (ps > pd)
{
for (; count != 0; count--)
*pd++ = *ps++; // Тут
}
else if (ps < pd)
{
for (ps += count, pd += count; count != 0; count--)
*--pd = *--ps; // И тут
}
}
Для меня понятно что именно делает данный метод. Для меня непонятно шаманство с указателями. Почему например в else if используется префикс, а в if постфикс? Можете разъяснить подробно?
Ответ
Все дело в инварианте цикла.
Когда идет побайтовое копирование "вперед" - указатели указывают на первый байт еще не обработанной области памяти:
----dddddddd---- ----ssssssss----
^ ^
| |
pd ps
Поэтому, на каждом шаге цикла происходит сначала копирование - потом сдвиг указателей:
*pd = *ps;
pd = pd + 1;
ps = ps + 1;
Запись *pd++ = *ps++ является более коротким способом записать три строчки выше. Используемая тут операция - постинкремент - увеличивает переменную, возвращая при этом старое значение переменной.
При копировании в обратную сторону - так получается, что указатель указывает на байт, идущий сразу после необработанного блока памяти:
----ssssssss---- ----dddddddd----
^ ^
| |
ps pd
Поэтому, на каждой итерации цикла его сначала сдвигают - а потом уже делают присваивание:
ps = ps - 1;
pd = pd - 1;
*pd = *ps;
Более коротко это записывается как *--pd = *--ps. используемая операция - предекремент - уменьшает переменную, возвращая новое значение переменной.
Комментариев нет:
Отправить комментарий