Просмотр полной версии : Объединение двух длинных строк
aaaSashaMGGU
16.05.2024, 15:44
Добрый день!
Хочу объединить две строки
Первая Str1: WSTRING(32000), вторая Str2: WSTRING(32000)
Обычный WCONCAT нельзя, т.к., там ограничение в 255
STU.StrConcatW(ADR(Str1), ADR(Str2), SIZEOF(Str2)) тоже нельзя, т.к., значение буфера SIZEOF не должно превышать тип INT 16384
Натыкался на идеи через указатели, но, может, есть у кого готовая проверенная временем функция?
Спасибо!
Отвечу заранее на вопрос "Зачем так много?": это нужно для формирования текстового файла-отчёта будущей длиной ~17кб
Евгений Кислов
16.05.2024, 16:34
Добрый день.
Если хочется "простых" решений - то в MemoryUtils есть функция MemCpy.
https://content.helpme-codesys.com/en/libs/MemoryUtils/Current/MemoryUtils/Functions/MemCpy.html
Отвечу заранее на вопрос "Зачем так много?": это нужно для формирования текстового файла-отчёта будущей длиной ~17кб
А по строкам или по частям нельзя в файл писать?
Или вместо строк вообще использовать буфер из массива байт?
aaaSashaMGGU
16.05.2024, 19:56
Добрый день.
Если хочется "простых" решений - то в MemoryUtils есть функция MemCpy.
https://content.helpme-codesys.com/en/libs/MemoryUtils/Current/MemoryUtils/Functions/MemCpy.html
Спасибо, будем смотреть
aaaSashaMGGU
16.05.2024, 19:59
А по строкам или по частям нельзя в файл писать?
Или вместо строк вообще использовать буфер из массива байт?
Так уж работает моя (пока ещё ненаписанная) программа. Сначала формируем длинную строку с текстом будущего письма, затем отправляем её в блок отправки Email-письма для дальнейшей обработки и отправки
Уже на этапе формирования в основном коде там будет ~17000 символов. Без наличия нормальной функции объединения уже и в основном коде никак
А там, где отправка письма - там да, там файл можно писать по строкам, конечно. Но и в этом случае, думаю, это не очень хорошо - дёргать жёсткий диск на запись десяти символов по сто раз. Уж про скорость всего этого отдельный вопрос
Тогда сделай вместо строки байтовый буфер. Ты сможешь туда копировать строки и набирать длинный буфер.
aaaSashaMGGU
16.05.2024, 20:59
На коленке получилось вот так:
FUNCTION SuperWConcat : BOOL //Объединение двух мега-строк в одну
VAR_INPUT
Address1: POINTER TO BYTE;
Address2: POINTER TO BYTE;
Address3: POINTER TO BYTE;
Len1: DWORD;
Len2: DWORD;
END_VAR
//Присваиваем
Memutils.MemCpy(Address3, Address1, Len1 * 2);
Memutils.MemCpy(Address3 + Len1 * 2, Address2, Len2 * 2);
//Бесполезный выход функции
SuperWConcat := FALSE;
Основной код для вызова:
PROGRAM qqq2
VAR
aaa1: WSTRING(64000) := "qwerty123";
aaa2: WSTRING(64000) := "йцукен456";
aaa3: WSTRING(64000) := "";
Temp : BOOL := FALSE;
END_VAR
Temp := SuperWConcat(ADR(aaa1), ADR(aaa2), ADR(aaa3), STU.StrLenW(ADR(aaa1)), STU.StrLenW(ADR(aaa2)));
В бою ещё не проверял, будем тестить
Всем спасибо
aaaSashaMGGU
16.05.2024, 21:12
Хотя, чего-то я сделал не то
В моём случае мне надо не объединять две строки в третью. А надо приписывать вторую в хвост к первой. Тогда всё работает вообще в одну строку даже без новой функции
PROGRAM qqq3
VAR
aaa1: WSTRING(64000) := "qwerty123";
aaa2: WSTRING(64000) := "йцукен456";
Temp : BOOL := FALSE;
END_VAR
IF Temp = TRUE THEN
Memutils.MemCpy(ADR(aaa1) + TO_DWORD(STU.StrLenW(ADR(aaa1))) * 2, ADR(aaa2), STU.StrLenW(ADR(aaa2)) * 2);
Temp := FALSE;
END_IF
Ты не забудь, что в конце готовой строки должен быть нулевой символ (два байта с кодом 0x00).
Возможно, его стоит явно добавлять в конец.
,,,,,,,,,,,,,,,,,,,,
aaaSashaMGGU
16.05.2024, 23:30
Ты не забудь, что в конце готовой строки должен быть нулевой символ (два байта с кодом 0x00).
Возможно, его стоит явно добавлять в конец.
Вроде, и так работает, без нулей этих... Ну, пусть будет с нулями...
Код:
PROGRAM qqq3
VAR
aaa1: WSTRING(1000) := "qwerty123";
aaa2: WSTRING(1000) := "йцукен456";
Temp : BOOL := FALSE;
END_VAR
IF Temp = TRUE THEN
SuperAddWString(ADR(aaa1), ADR(aaa2));
Temp := FALSE;
END_IF
Функция:
FUNCTION SuperAddWString : BOOL //Добавление второй строки в хвост первой
VAR_INPUT
AddressMain: POINTER TO BYTE; //Главная строка
AddressAdd: POINTER TO BYTE; //Добавочный кусочек
END_VAR
//Длины строк
VAR
Len1 : DWORD; //Длина главной строки
Len2 : DWORD; //Длина добавленного кусочка
END_VAR
//Массив двух нулевых байтов
VAR CONSTANT
Null : ARRAY[0..1] OF BYTE := [0, 0];
END_VAR
//Считаем длины строк
Len1 := TO_DWORD(STU.StrLenW(AddressMain)) * 2;
Len2 := TO_DWORD(STU.StrLenW(AddressAdd)) * 2;
//Присваиваем
Memutils.MemCpy(AddressMain + Len1, AddressAdd, Len2);
//Последние два байта запишем как нули
Memutils.MemCpy(AddressMain + Len1 + Len2, ADR(Null), 2);
//Бесполезный выход функции
SuperAddWString := FALSE;
Вроде, и так работает, без нулей этих... Ну, пусть будет с нулями...
Блин, сколько тебе лет? Я к тому, что обычно молодняку свойственно засирать темы вида "Ой! Сделал", "А, не, вот так надо", "Ещё вот сдела", "О, ещё доделал".
Боюсь оказаться старпёром, но ты разрабатываешь херово. С таким-то подходом. Мне хочется наорать и поохаживать тебя плёткой. Сортирую пинки:
1. ДАВНО уже ВЕЗДЕ есть кеширование записи на диски и флешки. После вызова API записи в файл данные сначала сохраняются в оперативной памяти контроллера диска (а фунция говорит, что всё записала), а потом через некоторое время контроллером диска физически записываются на диск (Flush Buffers).
И только если специально вызывать через API функцию сброса буферов на диск (Flush) - то запишутся сразу, чего ты и боялся.
Мог бы сохранять всё в файл кусками по 1-2 кб, например. И не выносить людям мозги.
2. Ты прям совсем жжошь. Кринжово. В стиле того программиста, которого я ругал на работе за то, что он указатели на NULL не проверял. После этого он уволился и пошёл в школу преподавать детям информатику. Может, ты его ученик? NULL - это НИЧЕГО, а не символ с кодом 0.
Правильно записать надо было через MemSet (установка значений в области памяти в заданные)!
(Надо Жене Кислову вообще рассказать этот анекдот про ADR(NULL)... как такое вообще работало?! И как компилятор пропустил зарезервированное ключевое слово?!)
(Дополню: Ага, я потом увидел что ты, используя зарезервированное ключевое слово, объвяил массив из двух байт. Это ещё кринжовее: всё намешано в хламину, чтобы враг не понял)
3. Конечно, "всё работало само", раз ты объявил это как WSTRING. Потому что компилятор WSTRING инициализирует нулями. Был бы это какой-то соданный на лету буфер - там валялся бы мусор из байтов, и конец строки не проставился бы автоматически.
4. (Тут уже приходит Женя Кислов со второй плёткой и распечаткой книги про Отладку проектов на ПЛК) ГДЕ ПРОВЕРКА ГРАНИЦ ДАННЫХ?! Какие данные в памяти ПЛК перезапишет (затрёт) твоя функция, если я подсуну ей в первый параметр WSTRING(10), а во второй WSTRING(12000)? У тебя ж нет проверок, хватит ли длины буфера!
Не задумывался, почему в функциях работы с памятью надо указывать длину буфера-то? Это не просто так.
5. А StrLenW проверил? Какой максимальный диапазон длины строки она будет обрабатывать? Хватит её на WSTRING(15000)?
Всё это мне напоминает моего двоюродного брательника, тоже Сашо. Он сначала делает, потом думает, потом переделывает. Ужас!
Евгений Кислов
17.05.2024, 09:31
И как компилятор пропустил зарезервированное ключевое слово?!)
В CODESYS V3.5 оно не является зарезервированным.
75814
как такое вообще работало?!
Применение к константным массивам (а также строкам и структурам) оператора ADR является синтаксически корректным.
По умолчанию не получится применить его к константам элементарных типов (INT и т. п.), но для обхода этого ограничения есть специальная галочка в настройках компиляции:
https://content.helpme-codesys.com/en/CODESYS%20Static%20Analysis/_san_rule_sa0007.html
Евгений Кислов Я сначала увидел ADR(NULL), а потом уже посмотрел, что он массив с таким именем объявил.
Всё равно правильно наорал: пусть границы данных в памяти проверяет.
Но и в этом случае, думаю, это не очень хорошо - дёргать жёсткий диск на запись десяти символов по сто раз.
В ПЛК2хх есть жёсткий диск? Не о том Вы думаете. С оптимизацией операций с диском должны драйвера ФС и дисковой подсистемы разбираться.
,,,,,,,,,,,,,,,,,,,,,,,,,
aaaSashaMGGU
17.05.2024, 13:24
Всем участникам спасибо, всё работает
Код скидывать не буду, а то опять скажете, что так не делается и вообще
Ну и - критиковать код, написанный на коленке в 23.30 дома, на Manjaro, в VirtualBox-е и поверхностно проверенный в эмуляторе (без реального контроллера); сама цель написания которого была в том, чтобы завтра на работе его прям с форума скопировать - и уже допилить до правильного состояния - ну такое себе
Будем справедливы: ты нас не предупредил, что это черновик. Ты сказал "Я сделал, вот код". Поэтому имеем то, что имеем.
Powered by vBulletin® Version 4.2.3 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot