Функция замены Arduino String и настраиваемая функция замены с массивом символов - PullRequest
0 голосов
/ 25 июня 2019

Я планирую чередовать некоторые строковые операции, особенно «заменить».Я видел несколько статей об эффективности типа String в Arduino (например, https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/). Конечно, просто использование String не вызывает проблем, но я подумал об эффективности времени объекта String. Поэтому я попытался обработать замену строки натолько символьные массивы.

Прежде всего, я сделал функцию замены, используя только некоторые из символьных массивов. Затем я попытался сравнить с традиционными операциями String, выполнив очень много одинаковых операций.Я не думаю, что эти два кода в точности совпадают из-за некоторых функций calloc (), но для использования функции, которую я считал calloc (), важно для моей функции.

Я использовал оценочную плату Nucleo-K432LC и Arduino 1.8.9.

#define strpos(A, B) (int) (strstr(A, B) - A)

char* replace_char(char* dst, char* needle, char* replacer) {
    int offset;
    int k;
    int ns, rep;
    char* temp;
    if (strlen(dst) + strlen(needle) < strlen(replacer) + strlen(dst)) {
        ns = strlen(replacer) - strlen(needle) + strlen(dst) + 1; rep = 1;
    }
    else {
        ns = strlen(dst) + strlen(needle) + 1; rep = 0;
    }
    temp = (char*)calloc(ns, sizeof(char));
    strcpy(temp, dst);
    if ((offset = strpos(dst, needle)) < 0) return NULL;
    for (k = 0; (k < strlen(replacer)) && replacer[k] != '\0'; ++k)
        temp[k + offset] = replacer[k];
    for (k += offset; k < strlen(replacer) - strlen(needle) + strlen(rep ? dst : temp); ++k)
        temp[k] = dst[k - strlen(replacer) + strlen(needle)];
    temp[k] = '\0';
    if (strpos(temp, needle) < 0) {
        dst = temp;
        return temp;
    }
    else
        return replace_char(temp, needle, replacer);
}

void setup() {
    Serial.begin(115200);
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
    unsigned long t0 = millis();

    for (int k = 0; k < 10000; ++k) {
        char* str = (char*) calloc(16, sizeof(char));
        char* str2 = "NANA";
        char* str3 = "1234KAHCS1234";
        strcat(str, "KKNANAHAHACA");
        char* newstr = replace_char(str, str2, str3);
        if (k >= 9999)
            Serial.println(newstr);
        free(str);
        free(newstr);
    }
    Serial.println(millis() - t0);

    unsigned long t1 = millis();
    for (int k = 0; k < 10000; ++k) {
        String str = "";
        String str2 = "NANA";
        String str3 = "1234KAHCS1234";
        str.concat("KKNANAHAHACA");
        str.replace(str2, str3);
        if (k >= 9999)
            Serial.println(str);
    }
    Serial.println(millis() - t1);

    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    delay(1000);
}

Мой STM32 сказал, что массив символов, использующий одну задержанную 600 мс и использовавший строку, вызвал задержку 468 мс. Окончательные результаты одинаковы для двух операций. Я попытался сократить длину аргументов, и функция показаласьчтобы работать успешно. Однако скорость была медленнее при операциях на основе символьных массивов.Также казалось, что для строковых операций не было ошибок.Я управлял эскизом в течение одного дня, но мне не удалось найти ни одного случая «эффективности».Я неправильно сфокусировался?Использование символьных массивов будет лучше, чем строковые операции?Или это снижение скорости вызвано исключительно нехваткой опыта программирования?

1 Ответ

1 голос
/ 25 июня 2019

Твоя функция просто ужасно написана. Это так плохо - даже анализ бессмысленно анализировать. Кстати, забудьте про рекурсию в развитии ОК. Всегда думай об алгоритме. Здесь у вас гораздо проще и определенно эффективнее:

char *findAndReplace(char *haystack, const char *needle, const char *repl)
{
    size_t needle_len;
    size_t repl_len;
    size_t haystack_len;
    const char *pos = strstr(haystack, needle);

    if(pos)
    {
        needle_len = strlen(needle);
        repl_len = strlen(repl);
        haystack_len = strlen(haystack);

        if(needle_len != repl_len)
        {
            memmove((void *)(pos + repl_len), (void *)(pos + needle_len), haystack_len - (pos - haystack) + 1);
        }

        memcpy((void *)pos, (void *)repl, repl_len);
    }
    return haystack;
}

конечно, стог сена должен быть:

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

но для использования функции я думал, что calloc () важен для моей функции.

Забудьте о malloc и друзьях при программировании ОК. В противном случае вы попадете в серьезные проблемы. Динамическое распределение памяти в малой памяти немного сложнее, и механизмы «большого компьютера» с треском проваливаются здесь

...