Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Выравнивание


Автор: sergioK1 12.4.2014, 08:27
попался такой код 
Код

#define UNALIGNED(X, Y) (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
#define DETECTNULL(X)   (((X) - 0x01010101) & ~(X) & 0x80808080)
 
char* _DEFUN (strcpy, (dst0, src0),
              char *dst0 _AND _CONST char *src0)
{
  char        *dst = dst0;
  _CONST char *src = src0;
         long *aligned_dst;
  _CONST long *aligned_src;
 
  /* If SRC or DEST is unaligned, then copy bytes. */
  if (!UNALIGNED(src, dst))
  {
    aligned_dst = (long*)dst;
    aligned_src = (long*)src;
 
    /* SRC and DEST are both "long int" aligned, try to do "long int" sized copies.  */
    while (!DETECTNULL(*aligned_src))
      *aligned_dst++ = *aligned_src++;
 
    dst = (char*)aligned_dst;
    src = (char*)aligned_src;
  }
 
  while (*dst++ = *src++) ;
 
  return dst0;
}


Что это за макросы и для чего ? где об этом ножно прочитать ?

Автор: feodorv 13.4.2014, 23:34
Цитата(sergioK1 @  12.4.2014,  09:27 Найти цитируемый пост)
Что это за макросы и для чего ? где об этом ножно прочитать ?

Простите ради Бога, но неужели для того, чтобы понять, что это за макросы, нужно обязательно прочитать о них где-нибудь??? Вырабатывайте навыки чтения чужого кода, который зачастую даже не комментирован.

То, что делается в приведённом коде, совершенно очевидно. Сначала проверяется, не выровнены ли адреса src и dst по четырёх-байтовой границе (или каков там размер лонга в байтах). Потому что именно в этом случае возможно соптимизировать копирование одной стоки в другую: становится возможным копировать не по одному байту, а сразу по четыре (или каков там размер лонга в байтах). Однако в этом случае нужно элегантно проверить копируемые 4 байта на завершающий строчку src ноль (ибо он и служит терминатором процесса копирования). 

Проверка на выравненность адреса выполняется путём тестирования последних бит адреса
Код
((long) ptr & (sizeof (long) - 1))
Поэкспериментируйте с размером лонга 2, 4, 8... 

Проверку на наличие нулевого байта в копируемых четырёх байтах осуществляет второй макрос DETECTNULL. Если не верите, потестируйте следующую программу:
Код
#include <stdio.h>

int main( void )
{
  int n;

  for( n = 0; n <= 0xff; n++)
  {
    int n1 = n - 0x01;
    int n2 = n1 & ~n;
    int n3 = n2 & 0x80;
    printf( "n = 0x%02x, n1 = 0x%02x, n2 = 0x%02x, n3 = 0x%02x\n",
      n & 0xff, n1 & 0xff, n2 & 0xff, n3 & 0xff);
  }

  return 0;
}



В ходе исследования приведённого кода может возникнуть несколько вопросов, например:
  • почему, если нашелся нулевой байт в копируемых четырёх байтах, то мы опять прибегаем к побайтовому копированию остатка строки;
  • что будет, если в копируемых четырёх байтах встретятся два нулевых байта, следующих друг за другом (ведь тогда вычитание единицы из последнего нулевого байта приведёт к дополнительному заёму из предшествующего нулевого байта);
  • зачем для объявления функции вдруг применяется очень сложная схема с макросами _DEFUN и _AND.

Автор: sergioK1 15.4.2014, 19:22
Цитата(feodorv @ 13.4.2014,  22:34)
Цитата(sergioK1 @  12.4.2014,  09:27 Найти цитируемый пост)
Что это за макросы и для чего ? где об этом ножно прочитать ?

Простите ради Бога, но неужели для того, чтобы понять, что это за макросы, нужно обязательно прочитать о них где-нибудь??? Вырабатывайте навыки чтения чужого кода, который зачастую даже не комментирован.

То, что делается в приведённом коде, совершенно очевидно. Сначала проверяется, не выровнены ли адреса src и dst по четырёх-байтовой границе (или каков там размер лонга в байтах). Потому что именно в этом случае возможно соптимизировать копирование одной стоки в другую: становится возможным копировать не по одному байту, а сразу по четыре (или каков там размер лонга в байтах). Однако в этом случае нужно элегантно проверить копируемые 4 байта на завершающий строчку src ноль (ибо он и служит терминатором процесса копирования). 

Проверка на выравненность адреса выполняется путём тестирования последних бит адреса
Код
((long) ptr & (sizeof (long) - 1))
Поэкспериментируйте с размером лонга 2, 4, 8... 

Проверку на наличие нулевого байта в копируемых четырёх байтах осуществляет второй макрос DETECTNULL. Если не верите, потестируйте следующую программу:
Код
#include <stdio.h>

int main( void )
{
  int n;

  for( n = 0; n <= 0xff; n++)
  {
    int n1 = n - 0x01;
    int n2 = n1 & ~n;
    int n3 = n2 & 0x80;
    printf( "n = 0x%02x, n1 = 0x%02x, n2 = 0x%02x, n3 = 0x%02x\n",
      n & 0xff, n1 & 0xff, n2 & 0xff, n3 & 0xff);
  }

  return 0;
}



В ходе исследования приведённого кода может возникнуть несколько вопросов, например:

  • почему, если нашелся нулевой байт в копируемых четырёх байтах, то мы опять прибегаем к побайтовому копированию остатка строки;
  • что будет, если в копируемых четырёх байтах встретятся два нулевых байта, следующих друг за другом (ведь тогда вычитание единицы из последнего нулевого байта приведёт к дополнительному заёму из предшествующего нулевого байта);
  • зачем для объявления функции вдруг применяется очень сложная схема с макросами _DEFUN и _AND.

 сам код Я понима, не понимаю 
откуда взяли математику под ним .  Что это за булевые операции?   Где про них прочитать ?

Автор: feodorv 15.4.2014, 21:30
Цитата(sergioK1 @  15.4.2014,  20:22 Найти цитируемый пост)
откуда взяли математику под ним

http://graphics.stanford.edu/~seander/bithacks.html или на русском http://mirknig.com/knigi/programming/35-algoritmicheskie_trjuki_dlja_programmistov.html.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)