LINUX.ORG.RU

То что сложно реализовать на других языках

 


0

3

Разбираюсь с библиотекой qsp и решил с вами поделится кусочком кода, а точнее реализация crc32. Автор кода, решил создать свой собственный crc32, на базе CRC-32/ISO-HDLC, взяв от туда таблицу, но изменил стартовое значение, и еще по мелочи:

int qspCRC(void *data, int len)
{
    unsigned char *ptr;
    int crc = 0;
    ptr = (unsigned char *)data;
    while (len--)
        crc = (qspCRCTable[(crc & 0xFF) ^ *ptr++] ^ crc >> 8) ^ 0xD202EF8D;
    return crc;
}

В чем прелесть: Использует int, но фактически работает как unsigned int. Вся логика на переполнение - и это как то работает, хотя вроде это UB. Автор кода крут (без шуток), я не спорю, но переписать это на любой другой язык, который будет контролировать переполнение - будет крайне сложно. Почему автор не использовал любой из стандартных алгоритмов crc, как он использовал библиотеку для regexp - загадка.

★★★★

Выглядит как самая обыкновенная дрисня на Си.

thegoldone ★★
()

Вся логика на переполнение - и это как то работает, хотя вроде это UB.

  1. А с чего ты решил что это UB?

  2. Такая же логика переполнения беззнакового числа на C#

uint a = uint.MaxValue;
a += 2;
Console.WriteLine(a);

//1
Ygor ★★★★★
()

переполнение

Не вижу математических операций.

anonymous
()
Ответ на: комментарий от Ygor

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 6.5/5 «If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.» crc - явно принимает значения больше INT_MAX - они и в таблице больше INT_MAX, 0xD202EF8D - это больше INT_MAX. Потому что изначально таблица была unsigned int

Silerus ★★★★
() автор топика

Автор кода, решил создать

Надо, больше, запятых, ставить, везде, вообще.

З.Ы. Ну так да, на си можно много чего написать, и оно даже будет работать. До поры до времени.

Zhbert ★★★★★
()

Использует int, но фактически работает как unsigned int.

А в чём сакральный смысл неиспользования unsigned? Если заменить int на unsigned int код сломается или будет работать дальше, только теперь уже без UB? ;)

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

именно сломается, так как есть старший бит знака в int, переполнение будет работать по другому. А вот сакральный смысл не знаю, это у автора надо спрашивать, но так как код старый - не факт что почта работает.

Silerus ★★★★
() автор топика
Ответ на: комментарий от Silerus

& и ^ работают одинаково для знаковых и беззнаковых. По другому работает только >>, он размножает старший (знаковый) бит вправо.

iliyap ★★★★★
()

но переписать это на любой другой язык… будет крайне сложно

Ты ещё к коду на Перле с такой меркой подойди. :) Там это не баг, а фича.

hobbit ★★★★★
()
Ответ на: комментарий от iliyap

в любом случае, если у этой функции и таблицы установить unsigned int результат вычисления будет другой - я проверял

Silerus ★★★★
() автор топика
Ответ на: комментарий от Silerus

именно сломается, так как есть старший бит знака в int, переполнение будет работать по другому.

Как именно? Ты код-то можешь скомпилировать и показать?

LamerOk ★★★★★
()
Ответ на: комментарий от Silerus

если у этой функции и таблицы установить unsigned int результат вычисления будет другой - я проверял

Запости весь код и ключи компиляции.

LamerOk ★★★★★
()
Ответ на: комментарий от Silerus

Конечно другой. Текущий crc ксорится со значением из таблицы — это одинаково для знаковых и беззнаковых. Результат сдвигается вправо на 8 бит — это одинаково для беззнаковых и положительных знаковых, но по разному для беззнаковых и отрицательных знаковых. Для беззнаковых и положительных знаковых слева добавляется 8 нулевых битов, а для отрицательных знаковых слева добавляется 8 единичных битов.

iliyap ★★★★★
()

Тут знаковое переполнение. Нет никакой гарантии что этот код будет выдавать одинаковый результат на разных архитектурах

mittorn ★★★★★
()

тут одни битовые операции и один сдвиг влево. причем знаковый. но похоже это ему жизнь не портит.

это не признак «мастерства». просто автор не понимает. что crc - как и любой хеш - беззнаковый, поскольку есть отображение на множество натуральных.

то есть у него уже прототип функции написан неверно.

alysnix ★★★
()
Ответ на: комментарий от Silerus

Знаковое переполнение из-за сдвига вправо? Или из-за xor? Я смотрю у вас тут своя атмосфера.

kipar_2024
()
Ответ на: комментарий от alysnix

это уже не исправишь - считай формат, так как это кусок, популярного в узких кругах, движка текстовых квестов, типа renpy

Silerus ★★★★
() автор топика
Ответ на: комментарий от mittorn

От xor с 0xD202EF8D

у битовых операций вообще нет переполнения. поскольку там нет переноса. но знаковый сдвиг вправо оставляет знак на месте. по идее может выставляться sign бит.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)

Какой-то crc32 то будет считать и он будет работать. Другое дело на иной платформе рассчитанный таким алгоритмом crc32 может дать другое значение.

Psilocybe ★★★★★
()
Ответ на: комментарий от Silerus

crc >> 8

вот эта фигня с вопросом. раз crc знаковый, то старший бит crc будет неизменный, это явно дает некую корреляцию, и будет весь хеш делать с некими отклонениям от нормального распределения.

похоже автора это не особо заботит, и ему пошел бы любой нормальный хеш, просто автор решил идти в пропасть непроторенными дорогами.

alysnix ★★★
()
Ответ на: комментарий от Silerus

Ну это ты написал еще в ОП-посте, я хотел узнать названия языка где есть «контроль переполнения» что не дает реализовать этот алгоритм.

MOPKOBKA ★★★★★
()
Ответ на: комментарий от alysnix

тут одни битовые операции и один сдвиг влево.

разумеется там сдвиг вправо. просто в москве неприличная жара(+35С) и расплавление воздухов.

alysnix ★★★
()
Ответ на: комментарий от Silerus

Код с уб-шным багом, правый шифт отрицательного int crc (а что ему помешает стать таковым) однозначно УБ, и это действительно трудно повторить в других языках

zurg
()
Ответ на: комментарий от LamerOk

Спросите еще тех, кто писал дриснёвый struct pollfd и догадался хранить битовые флаги в знаковом числе.

PPP328 ★★★★★
()
Ответ на: комментарий от Silerus
function qspCRC(data) {
  let ptr = 0, crc = 0, len = data.length;  
  while (len--) 
    crc = (qspCRCTable[(crc & 0xFF) ^ data.charCodeAt(ptr++)] ^ crc >> 8) ^ 0xD202EF8D;
  return crc;
}
> console.log(qspCRC('hello world'));
-449350184
MOPKOBKA ★★★★★
()

Да отсутствие обязательного контроля переполнения int в половине языков, наверное. Даже в Java можно написать такой же алгоритм.

А в популярных языках, где нельзя, часто вопрос не в защите от переполнения, а в бесконечных int (честная длинная арифметика в Python, float в JavaScript и т. д.). Что позволяет написать кучу других «смотри как я могу» алгоритмов, которые будут портянкой на С.

А в чём крутость использования int, а не unsigned int или даже uint32_t (если хочется поддерживать дремучие компиляторы без stdint, то можно надефайнить свои аналоги как делают всякие либы) для меня загадка.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от MOPKOBKA

("", 0x00000000), // Пустая строка («a», -390611389), // Одиночный ASCII символ («test», 662733068), // ASCII строка («привет», 957064684), // UTF-8 строка («Hello, world!», 1782682705), // Длинная строка справа - это то что посчитала с функция

Silerus ★★★★
() автор топика
Ответ на: комментарий от zurg

Это не уб, а определяется имплементацией. Хотя что им мешало делать просто арифметический (с сохранением знака бит), как стандарт - непонятно.

тут и проблемы никакой нет. знаковый операнд - знаковый сдвиг. беззнаковый операнд - чисто битовый сдвиг с задвиганием нуля в старший разряд.

alysnix ★★★
()
Ответ на: комментарий от Silerus

Я про JS пишу, у него строки не байтовые. Нужно использовать буфер байтов что бы все правильно работало.

MOPKOBKA ★★★★★
()
Ответ на: комментарий от iliyap

Результат сдвигается вправо на 8 бит — это одинаково для беззнаковых и положительных знаковых, но по разному для беззнаковых и отрицательных знаковых. Для беззнаковых и положительных знаковых слева добавляется 8 нулевых битов, а для отрицательных знаковых слева добавляется 8 единичных битов.

а для отрицательных знаковых слева добавляется 8 единичных битов.

Сдвиг вправо для отрицательных чисел - это implementation-defined. Могут насыпать как нулей, так и единиц.

LamerOk ★★★★★
()
Ответ на: комментарий от alysnix

что им мешало делать просто арифметический (с сохранением знака бит), как стандарт - непонятно.

The Committee has affirmed the freedom in implementation granted by the Base Document in not requiring the signed right shift operation to sign extend, since such a requirement might slow down fast code and since the usefulness of sign extended shifts is marginal.

LamerOk ★★★★★
()
Ответ на: комментарий от Silerus

Ты просто неправильно функцию написал, возьми мою, и вызови вот так:

function qspCRC(data) {
  let ptr = 0, crc = 0, len = data.length;  
  while (len--) 
    crc = (qspCRCTable[(crc & 0xFF) ^ data[ptr++]] ^ crc >> 8) ^ 0xD202EF8D;
  return crc;
}

console.log(qspCRC(new Buffer.from('привет')));

...
957064684
Тоже самое и с Python.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от LamerOk

might slow down fast code and since the usefulness of sign extended shifts is marginal.

вот. это не УБ. это просто в комитете не определились, что со знаком делать. но вроде gcc и clang не парятся, и делают знаковый шифт в таком случае.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

‘Empty: OK (got 0, expected 0)’ «‘a’: OK (got -390611389, expected -390611389)» «‘test’: FAIL (got -863718235, expected 662733068)» «‘привет’: FAIL (got -721927907, expected 957064684)» Вставил твою функцию

Silerus ★★★★
() автор топика
Последнее исправление: Silerus (всего исправлений: 1)
Ответ на: комментарий от alysnix

но вроде gcc и clang не парятся, и делают знаковый шифт в таком случае.

А потом это говно или утекает в сеть или в рамках той же фирмы кто-то копипастит его в Keil.

PPP328 ★★★★★
()
Ответ на: комментарий от Silerus

Вот код + вывод, не разобрался как на твоем сайте что то редактировать: https://onecompiler.com/nodejs/43qcmy7tu

На Rust и Go тоже должно работать, если перепишешь один в один.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.