В коде нет ничего хитрого, но это не очень хорошо.На самом деле, это очень плохо, и не из-за стиля, а потому, что он портит память.
(2) int length = strlen(buf)>>3;
Эта строка вычисляет все количество long
объектов, которые помещаются в строку, предполагая, что long
восемь байтов (/ sizeof(long)
следует использовать вместо >>3
) и что int
достаточно велико, чтобы вместить число (int
следует использовать вместо *1010*).
(3) long *a = (long*) (buf + length);
Кажется, это намеревается установить a
для указания фрагмента в конце строки, который недостаточно длинный, чтобы содержать другой объект long
.Однако, поскольку length
- это число long
объектов, а buf
действует как указатель на char
, его арифметика неверна.Он вычисляет buf
плюс length
char
объектов, когда намеревается вычислить buf
плюс length
long
объектов.Следует использовать (long *) buf + length
.Кроме того, предполагается, что char *
с произвольным выравниванием может быть разумно преобразовано в long *
, что не гарантируется стандартом C.
(5) int len = strlen((char*)a);
Это вычисляет количество байтов во фрагменте.Это пустая трата времени, потому что код предварительно рассчитал длину строки.Он мог бы сохранить эту длину и получить коэффициент и остаток по модулю long
вместо повторного вызова strlen
.
(6) long total_count = bit_count((long*) buf, length);
Это вычисляет количество битов, установленных в основной части буферачасть, которая обрабатывается как некоторое целое число long
объектов.Как и при предыдущем преобразовании, предполагается, что char *
может быть преобразовано в long *
, и, кроме того, вызываемая им подпрограмма использует этот указатель для чтения long
объектов из объекта, не определенного как массив long
, тем самым нарушая правила псевдонимов C.
(7) *a = (*a) & (((long)1<<(len*8))-1);
Напомним, что a
указывает на некоторое количество конечных байтов в строке.(long)1<<(len*8)
перемещается немного выше этого количества байтов, предполагая, что байты составляют восемь битов (вместо 8
следует использовать CHAR_BIT
).(Например, если есть два байта, это создает значение 10000 16 .) Затем вычитание одного создает битовую маску для байтов (FFFF 16 в примере).Затем *a
пытается прочитать long
с конца строки, после чего применение маски с &
уменьшает значение, считываемое до байтов в строке.Это не только снова нарушает правила псевдонимов C, но также читает вне памяти buf
, который имеет неопределенное поведение.Наконец, оператор записывает обновленное значение в *a
, что еще хуже - если вам не понравилось чтение за пределами buf
, теперь код пишет за пределами buf
, что приводит к повреждению где-то неизвестно.
(8) char *c = (char*)a;
Эта строка бесполезна, поскольку c
никогда не используется.
(9) total_count += bit_count(a,1);
Подсчитывает количество битов, установленных в long
, который был обновлен в (7).
В подпрограмме bit_count
мы обнаруживаем, что код считает биты один за другим.Это абсурд.Нарушение правил C о наложении псевдонимов могло бы иметь некоторое преимущество в производительности при обработке целых long
объектов вместо отдельных char
объектов, если используемая конкретная реализация C позволяла создавать псевдонимы с невыровненными адресами.Но этот код просто выполняет побитовую обработку;он не получает никакого преимущества от какой-либо инструкции по подсчету битов (также известной как подсчет населения) на процессоре.
Кроме того, подпрограмма bit_count
признает, что для подсчета битов следует использовать unsigned long
, поскольку он определяет word
как unsigned long
.Но он не может распознать, что должен был использовать unsigned long
повсюду, так как long
может иметь представление прерывания, которое приведет к сбою кода.
Он также определяет b
, даже не используя его.