LINUX.ORG.RU

memcmp вместо strncmp для оптимизации?

 , , memcmp, strncmp


0

2

Приветствую.

Построено у меня взаимодействие с тысячами железок через mqtt сервер, из всего многообразия «сообщений» приходящих через либу в типе char * msg есть пересылка снимков в jpeg, которые тоже приходят одномоментно тысячами штук на свой сервис, весь «парсинг заголовка сообщения» на этом сервисе выполнял обычным strncmp и для жпега это выглядит как

if (!strncmp(msg, "\xFF\xD8\xFF", 3)) { ... }
else if ...

как я понимаю memcmp быстрее strncmp, тем более мне нужно сравнить байты а не строки и понятно что так тоже как минимум компилируется

if (!memcmp(msg, "\xFF\xD8\xFF", 3)) { ... }

а можно БЕЗ объявления переменной выполнять сравнение набора байт любой длины?

мне такой в голову пришел перл, но что то сомнительна его производительность )

if (memcmp(msg, std::array<uint8_t,3>({0xFF, 0xD8, 0xFF}).data(), 3) == 0)
★★★

БЕЗ объявления переменной выполнять сравнение набора байт любой длины?

Чавой? Как это должно работать?

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

как то же работают(компилируются) варианты memcmp(msg, "\xFF\xD8\xFF", 3) и memcmp(msg, std::array<uint8_t,3>({0xFF, 0xD8, 0xFF}).data(), 3)

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

Ну я переменную вижу, а как без переменной?

Bfgeshka ★★★★★
()

Вариант с «\xFF\xD8\xFF» намного читаемее огорода с std::array.

annulen ★★★★★
()

И вообще штуки вроде временный_контейнер().data() внутри аргументов функции это антипаттерн, так как в более сложном случае можно легко получить use-after-free из-за преждевременного удаления временного контейнера

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от annulen
cpp:299:41: error: cannot convert ‘<brace-enclosed initializer list>’ to ‘const void*’
  if (memcmp(msg, {{0xFF, 0xD8, 0xFF}}, 3) == 0)
                                         ^
In file included from /usr/include/c++/8/cstring:42,
                 from Downloader.cpp:3:
/usr/include/string.h:63:50: note:   initializing argument 2 of ‘int memcmp(const void*, const void*, size_t)’
 extern int memcmp (const void *__s1, const void *__s2, size_t __n)

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

:)

1
error: expected primary-expression before ‘[’ token
  if (memcmp(msg, uint8_t[3]{0xFF, 0xD8, 0xFF}, 3) == 0)

2
error: expected primary-expression before ‘[’ token
  if (memcmp(msg, uint8_t[]{0xFF, 0xD8, 0xFF}, 3) == 0)

3
: warning: ISO C++ forbids compound-literals [-Wpedantic]
  if (memcmp(msg, ((uint8_t[3]){0xFF, 0xD8, 0xFF}), 3) == 0)
                                                ^
.cpp:299:31: error: taking address of temporary array
  if (memcmp(msg, ((uint8_t[3]){0xFF, 0xD8, 0xFF}), 3) == 0)
                  ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
wolverin ★★★
() автор топика
Ответ на: комментарий от Bfgeshka

Можешь объяснить, чего ОП хочет именно? Чтобы не было литерала строки?

Да я сам не понимаю. Возможно, ОП думает, что строковый литерал является внутри не тупым массивом char, а чем-то ещё.

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

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

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

Строковый литерал является const char*. Если добавить const, то код выше наверное скомпилируется. Но это нечитаемый трэш.

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

Тебе бы глянуть, как эльф скомпонован. Эта шиза с приведением анонимного массива вообще не в тему.

Я тебе больше скажу - твои три чара влезают в один u64, вог бы просто их все запихать туда и сравнивать без отдельной функции.

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

ну 3 чара это просто частный случай, так то да можно записать в переменную и сравнить с константой

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

Тебе бы глянуть, как эльф скомпонован.

Литералы и прочие константы времени компиляции идут в .rodata, и могут не выравниваться. Теоретически, если у него таких массивов много, то эти концевые нули могут во что-то сложиться, и rodata в памяти займёт на одну страницу больше, а это уже целых 4K.

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

Техническотеоретически да, но он очевидно ловит мб несколько типов файлов топс.

И вообще, тогда литералы как раз лучше использовать по порядку нужности, будет необходимо контекст перестраивать. Или писать участок на асме луше поможет.

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

И вообще, тогда литералы как раз лучше использовать по порядку нужности, будет необходимо контекст перестраивать

Если это действительно сранвение литералов в цикле по очереди, то можно даже какой-нибудь re2c задействовать (или gperf), чтобы в один проход сматчить.

Или писать участок на асме луше поможет.

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

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

твои три чара влезают в один u64, вог бы просто их все запихать туда и сравнивать без отдельной функции.

Я почти уверен, что ты с 1 раза корректный код для описанного приёма не напишешь. А он тем более.

firkax ★★★★★
()

весь «парсинг заголовка сообщения»

Я правильно понял, что ты не полагаясь на разбор сообщения своим сервером напрямую парсишь сообщеньки?

мне нужно сравнить байты а не строки

Так может тебе и надо сравнить байты а не массивы?

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

сервер mqtt не разбирает сообщения, я могу только разделить по веткам, но их уже и так столько, что начинает сложно вспоминать кто куда подписан должен быть и что куда приходит, сервис так вообще подписан по маске на топик(-и).

если смотреть на количество видов сообщений, то больше просто строк, просто количество каких пересылается не оценивал, очевидно в размере больше jpeg, от которых проверяю только первые 3 байта штатного заголовка.

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

могу только разделить по веткам, но их уже и так столько, что начинает сложно вспоминать кто куда подписан должен быть и что куда приходит, сервис так вообще подписан по маске на топик(-и)

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

ya-betmen ★★★★★
()
Последнее исправление: ya-betmen (всего исправлений: 1)
Ответ на: комментарий от wolverin

У меня такое ощущение, что ты пытаешься изучать плюсы по советам из интернета, как-будто это какой-то питон. Плюсы такое не любят и жестоко за это наказывают, причём месть может оказаться сильно отложенной. Так что советую найти опытного коллегу, который будет ревьюить весь твой код. Или писать на более простом языке.

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

Да, гогнокод, оно ещё и без компилятора не соберётся!

Bfgeshka ★★★★★
()

А вообще, автор, не беспокойся, компилятор оптимизирует этот memcmp и никакого лишнего нуля там не будет, да и вообще этот литерал он в виде строки никуда не сохранит

https://godbolt.org/z/hdGWfPnhs

firkax ★★★★★
()

Преждевременная оптимизация

https://godbolt.org/z/vEP8facjc

Компилятор заменил вызов strncmp на команду сравнения с константой

anonymous
()

что то сомнительна его производительность

Практика главный критерий истины. У тебя профайлер отобрали? Руки отнялись?

cobold ★★★★★
()

Это разница которая видна лишь в коде, а не в итоговом файле. Что с переменной, что без нее, нужно выделить место под массив который будет передан в memcmp.

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

Разница в том что со строкой этот массив будет из 4 байт, а с массивом - из 3. Впрочем как уже выше показано, на современном компиляторе массива вообще не будет, как и memcmp-а.

firkax ★★★★★
()
Ответ на: комментарий от ya-betmen

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

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

С этим не спорю, я отвечаю на вопрос в начальном посте. И массив и строку можно передать как с объявлением переменной, так и без.

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

memcmp не нужно проверять ноль, поэтому он должен быть немного лучше.

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