Pull to refresh

Comments 24

Везде где есть циклы for и while будет огромное поле для ошибок. Разве не для ибегания этого придумали STL в C++?

В первом примере хочется (в C++) передавать const аргумент, тогда ошибку заметит компилятор.

Всегда топлю за const-correctness. Не панацея, но хотя бы подобного рода ошибок позволяет избежать.


В качестве возражения Андрею, допускаю, что memcpy() может быть реализовать более оптимально, нежели strcpy(): не нужно проверять признак конца строки, можно копировать словами и т.п. С другой стороны, там несколько раз считается длинна строки через strlen()...

Дык не считайте её — посчитайте один раз и положите в переменную — длина же не меняется на протяжении этой функции.

ПС
Вообще пример 1 — это бред сивой кобылы имхо — если такое пишут внутри ОС — за это надо наказывать у позорного столба

ПС2
А зачем вообще коллекционировать функции копирования памяти? Одно то что таковые наличествуют в коде — говорит о том, что это странный код и странный программист, который решил переписывать стандартные решения на свои костыли(если конечно это не разработчик стандартной библиотеки для какого либо компилятора, делающий это для оптимизации конкретно под него)
не считайте её — посчитайте один раз и положите в переменную

О том и речь, если автор кода думал о производительности, используя memset(), то почему он длину считает несколько раз?


Вообще пример 1 — это бред сивой кобылы имхо — если такое пишут внутри ОС — за это надо наказывать у позорного столба

Это вариант strdup со своим распределителем. В ядре может быть уйма распределителей памяти под разные критерии. К примеру, для DMA могут быть критичными требования непрерывности блока в физической памяти. А для остальных подсистем — достаточно непрерывного блока виртуальной памяти. Какой-то распределитель по-умолчанию выделяет из некешируемой памяти (для взаимодействия с другими аппаратными блоками, к примеру) и так далее. Так что если по существу, опишите, что не так?


Одно то что таковые наличествуют в коде — говорит о том, что это странный код и странный программист

Я странный программист, я написал необходимое подмножество стандартной библиотеки и C++ рантайма для используемого проекта на контроллере, что позволило сэкономить 120кБ из 300кБ доступных для кода.

Для пример 2 нельзя разве сделать
while (n != 0)
{
--n;
*cdest++ = *csrc++;
}
а для 32 разрядных можно немного увеличить размер и сделать копирование по 4 байта если
((csrc & 0x3 == 0) && (cdest & 0x3 == 0) && n >= 4)
или по 2 байта если
((csrc & 0x1 == 0) && (cdest & 0x1 == 0) && n >= 2)
?
а для 32 разрядных можно немного увеличить размер и сделать копирование по 4 байта

Если нужен оптимизированный код, а каких-то специальных требований нет — используйте memcpy, а не изобретайте велосипеды. Выше вероятность допустить ошибку в подобном коде.

Этот ответ надо перенаправить писателям примера 2. Я и так использую memcpy.
Для пример 2 нельзя разве сделать

Читать такой код сложнее, а преимущества неочевидны. Современные компиляторы всё равно эти циклы оптимизируют. Например, clang использует инструкцию movups из SSE. Не факт, что вариант с while сэкономит память или будет быстрее.


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

Впрочем, в libgcc используется такой вариант:


#include <stddef.h>

void *
memcpy (void *dest, const void *src, size_t len)
{
  char *d = dest;
  const char *s = src;
  while (len--)
    *d++ = *s++;
  return dest;
}

Но он и написан 9 лет назад, да и GCC менее агрессивно такие случаи оптимизирует при -O2.

*d++ = *s++; какой же жестяк…

Почему? Достаточно популярная конструкция.

А в чём, собственно, проблема?
Вы видите более приемлемый вариант? По какому критерию?

Ну вот эти два плюсика в конце, да ещё и дважды в одном выражении. Во всех мейнстримовых языках от них давно отказались. А ещё они бывают и вначале переменной.
Жалко, что первое апреля прошло. Иначе было бы хорошей шуткой: «В рамках программы переведения с++ в „мейнстримовый язык“, от обеих форм операторов „++“ и „--“ отказались. Вследствие этого „с++“ тоже пришлось переименовать. По логике, просто отказались от „++“. Но потом кто-то подсказал, что язык с названием „с“ уже существует...»

А если серьёзно, код, который Вам не понравился — нормальный код для с. Да и для с++, в общем-то, тоже не вижу криминала.

Да ну, серьёзно?
Java, C# — не мейнстрим? Kotlin?
Инфиксные, да, есть не везде, но это чисто синтаксические заморочки авторов.

Достал из закромов свой велосипед очень большой давности.


char* newStr(const char* s, int n) {
    if (!s) {
        return 0;
    }
    char* result = new char[n + 1];
    strncpy(result, s, n);
    result[n] = '\0';
    return result;
}
Если реально строка очень короткая, делаете бессмысленную работу: strncpy() заливает весь хвост буфера NULами.
(Хотя полезно для копирования паролей и т.п. — чтобы нельзя было косвенно узнать длину.)
Ну и случай превышения входной строкой указанной длины не ловится.

Слишком длинная строка обрежется до указанной длины.

Я о том, что оно обрежется молча.

Если следовать описанию в стандарте — можно много вещей проигнорировать, как и во всяких strcpy.
Да, анализатор, к сожалению, читать пока не умеет — потому могут быть интересные срабатывания.

Sign up to leave a comment.