из String в char* array
- Войдите на сайт для отправки комментариев
Вс, 10/03/2019 - 20:22
есть прототип функции перекодировки для дисплеев
пртотип
char* utf8rus(char *source) {
uint8_t i = 0;
unsigned char n;
uint8_t k = strlen(source);
char m[2] = {'0', '\0'};
char* target = (char*)malloc((k + 1) * sizeof(char));
free(target);
while (i < k) {
n = source[i]; i++;
if (n >= 0xC0) {
switch (n) {
case 0xD0: {
n = source[i]; i++;
if (n == 0x81) {
n = 0xA8;
break;
}
if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
break;
}
case 0xD1: {
n = source[i]; i++;
if (n == 0x91) {
n = 0xB8;
break;
}
if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
break;
}
}
}
m[0] = n; strcat(target, m);
}
return target;
}
после переделки получилось два варианта, оба рабочие
1 вариант
char* utf8rus(char *source) {
uint8_t i = 0;
unsigned char n;
uint8_t k = strlen(source);
char m[2] = {'0', '\0'};
char* target = (char*)malloc((k + 1) * sizeof(char));
free(target);
while (i < k) {
n = source[i]; i++;
if (n >= 0xC0) {
switch (n) {
case 0xD0: {
n = source[i]; i++;
if (n == 0x81) {
n = 0xA8;
break;
}
if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
break;
}
case 0xD1: {
n = source[i]; i++;
if (n == 0x91) {
n = 0xB8;
break;
}
if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
break;
}
}
}
m[0] = n; strcat(target, m);
}
return target;
}
2 вариант
char* utf8rus(char *source) {
uint8_t i = 0;
unsigned char n;
uint8_t k = strlen(source);
char* target = (char*)malloc((k + 1) * sizeof(char)), *ptr = target;
free(target);
while (i < k) {
n = source[i]; i++;
if (n >= 0xC0) {
switch (n) {
case 0xD0: {
n = source[i]; i++;
if (n == 0x81) {
n = 0xA8;
break;
}
if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
break;
}
case 0xD1: {
n = source[i]; i++;
if (n == 0x91) {
n = 0xB8;
break;
}
if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
break;
}
}
}
*ptr++ = n;
}
*ptr = 0;
return target;
}
есть ли ошибки, и какой более лучший?
протоип не верный в первом посте, ниже верный
прототип
String utf8rus(String source) { uint8_t i, k; String target; unsigned char n; char m[2] = { '0', '\0' }; k = source.length(); i = 0; while (i < k) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } m[0] = n; target = target + String(m); } return target; }При возврате указателя на освобождённую область памяти все три варианта очень странные.
если не очищать память, то будет переполнение памяти
Тут все сплошная ошибка и грабли.
покажите как бы вы сделали
Если source не нужно сохранять в целости и сохранности, то писать rus прямо в его область, в финале затерминировать и возвратить на него указатель.
source мне не нужен после обработки
один из вариантов - заранее выделить массив char для результата в основной программе и передать ссылку на него в функцию перекодировки
один из вариантов - заранее выделить массив char для результата в основной программе и передать ссылку на него в функцию перекодировки
да я об этом думал, но могу забыть потом сделать free();
source мне не нужен после обработки
Ну, вот в фаре накидал, над оптимизацией не думал, в МК не заливал.
char* utf8rus(char* source) { byte *ptrRead, *ptrWrite; ptrRead = ptrWrite = (byte*) source; while (*ptrRead) { *ptrWrite = *ptrRead; if (*ptrRead >= 0xC0) { switch (*ptrRead) { case 0xD0: { ptrRead++; if (*ptrRead == 0x81) { *ptrWrite = 0xA8; break; } if (*ptrRead >= 0x90 && *ptrRead <= 0xBF) { *ptrWrite = *ptrRead + 0x30; } break; } case 0xD1: { ptrRead++; if (*ptrRead == 0x91) { *ptrWrite = 0xB8; break; } if (*ptrRead >= 0x80 && *ptrRead <= 0x8F) { *ptrWrite = *ptrRead + 0x70; } break; } } } ptrRead++; ptrWrite++; } *ptrWrite = 0x00; return source; }да я об этом думал, но могу забыть потом сделать free();
для глобальных переменных забыть почистить память - это куда менее опасно, чем для переменных в функции
sadman41, проверил ваш код, не работает, в конце слов всякие каракули добавляет
Запостите от своего краткий рабочий пример, я прогоню на нём.
краткий не получится, у меня по 26 слов на двух языках в прогмеме лежит, с возможностью переключения языков на лету
Ну, что там..
char text[]="UTF-8 here";
utf8rus(text);
Serial.println(text);
sadman41, успели забрать
А где там, кстати, String? Чёт я его там и не заметил. Его там вообще нет ни в одном из кодов.
пост #1
ну так подскажите как лучше сделать
пост #1
ну так подскажите как лучше сделать
andriano, а как лучше, сразу выделить память, или уже внутри функции по размеру слова?
Valera19701, а Вы ответьте какая розетка лучше сетевая или юсб. Вот так и здесь. Если навыков работой с кучей маловато, то просто выделите глобальный буфер. А иначе работайте с кучей оперируя указателями. Ну а если вообще асс, то организуйте класс подобный String. Вот такие пироги с котятами.
Проблем у себя не вижу
void strAsHex(char* source) { char *ptrRead = source; while (*ptrRead) { Serial.print(" 0x"); Serial.print((byte) *ptrRead, HEX); ptrRead++; } Serial.println(); } char* utf8rus(char* source) { byte *ptrRead, *ptrWrite; ptrRead = ptrWrite = (byte*) source; // Serial.println(" --- "); while (*ptrRead) { *ptrWrite = *ptrRead; // Serial.print("in: 0x"); Serial.println(*ptrWrite, HEX); if (*ptrWrite >= 0xC0) { switch (*ptrWrite) { case 0xD0: { ptrRead++; // Serial.print("in: 0x"); Serial.println((byte) *ptrRead, HEX); if (*ptrRead == 0x81) { *ptrWrite = 0xA8; break; } if (*ptrRead >= 0x90 && *ptrRead <= 0xBF) { *ptrWrite = *ptrRead + 0x30; } break; } case 0xD1: { ptrRead++; // Serial.print("in: 0x"); Serial.println((byte) *ptrRead, HEX); if (*ptrRead == 0x91) { *ptrWrite = 0xB8; break; } if (*ptrRead >= 0x80 && *ptrRead <= 0x8F) { *ptrWrite = *ptrRead + 0x70; } break; } } } // Serial.print("out: 0x"); Serial.println((byte) *ptrWrite, HEX); ptrRead++; ptrWrite++; } *ptrWrite = 0x00; // Serial.println(" --- "); return source; } void setup() { char text[] = "ПРИВЕТ МИР"; Serial.begin(115200); Serial.print("(1) text: "); Serial.println(text); strAsHex(text); utf8rus(text); Serial.print("(2) text: "); Serial.println(text); strAsHex(text); } void loop() {}Вывод:
sadman41, у вас есть дисплей ssd1306? я вам весь код с библиотекой дам
sadman41, у вас есть дисплей ssd1306? я вам весь код с библиотекой дам
а зачем оно ему? - вы не верите Садману. что он реально протестировал свой код?
andriano, а как лучше, сразу выделить память, или уже внутри функции по размеру слова?
"— Мне водки прям сейчас выпить? Иль уж потом за ужином сразу?" (Мышлаевский):)
у меня его код неправильно отображает
ЕвгенийП, а по существу?
andriano, а как лучше, сразу выделить память, или уже внутри функции по размеру слова?
В большинстве случаев лучше второй вариант, но только при условии, что при этом не происходит фрагментации памяти. Если опасность фрагментации есть, лучше, естественно, выдалить буфер заранее и фиксированного размера.
PS. Ни лично я предпочитаю библиотеки, в которых не нужно ничего перекодировать.
sadman41, у вас есть дисплей ssd1306? я вам весь код с библиотекой дам
Ну, где-то валялся, конечно. Но, как я успел увидеть, вы символы в функцию не через выделенный фрагмент памяти передаете, а из прогмемов и как display.print(..., "абвгджз...");
В последнем случае, как мне кажется, компилятор временно создаёт анонимный char[], передаёт указатель на него и после выхода из функции сразу уничтожает. Так что тут проблемы на пустом месте возникнуть могут.
Изначально вы пытались из char[] в char[] перегнать - я вам такую функцию и написал. Она ожидает, что вы сформируете UTF-8 строку в памяти (копированием, например), скормите её перекодировщику и передадите в print(). На иные варианты я не ориентировался.
andriano, в том то и вся соль, что есть утечка памяти, поэтому и засунул free() во внутрь функции
andriano, в том то и вся соль, что есть утечка памяти, поэтому и засунул free() во внутрь функции
странное решение
есть прототип функции перекодировки для дисплеев
Функция utf8rus(), работающая с char-строками, опубликована в посте #40:
http://arduino.ru/forum/programmirovanie/rusifikatsiya-biblioteki-adafru...
arduinec, спасибо, хотел чтобы с динамическим массивом работало
ЕвгенийП, а по существу?
Это и было по существу.
в том то и вся соль, что есть утечка памяти, поэтому и засунул free() во внутрь функции
Совершенно секретно. Перед прочтением уничтожить.
(это тоже по существу, если что).
а если так ?
char* target = new char(); char* utf8rus(char *source) { uint8_t i = 0; unsigned char n; uint8_t k = strlen(source); memset(target, '\0', k + 1); char* ptr = target; while (i < k) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } *ptr++ = n; } *ptr = 0x00; return target; }А в варианте из первого комментария с использованием String в функции будет создан локальный объект, а затем при возврате из функции он будет скопирован (создан новый с тем же значением), а локальный объект будет удален. И утечки памяти не должно быть. Разве нет?
1.
не вижу вызова этой функции, потому не понимаю как Вы собрались передавать ей параметр.
2.
строка №34 не нужна
3.
в строке №1 запрашивается 1 (один) байт памяти, а в строке №6 в этот самый один байт Вы пытаетесь впихнуть k / 2 + 1 байтов. Значит, при k >= 2 оно туда не поместится. Более того, в строке №32, Вы пытаетесь пихать туда уже k байтов. А запрашивали только один.
4.
Строка №5 допустима только в случае, если в "значимой части" source нет нулей. В Вашем случае это так? Мне что-то кажется. что нули там имеют право быть. Или нет? Если нет, то так можно.
Ну, пока хватит.
каким образом он добавляет сам элементы массива?
char* target = new char(); char* utf8rus(char *source) { Serial.print(source); Serial.print(" : "); Serial.print(strlen(target)); Serial.print(" : "); uint8_t i = 0; unsigned char n; uint8_t k = strlen(source); memset(target, '\0', k + 1); Serial.print(strlen(target)); Serial.print(" : "); char* ptr = target; while (i < k) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } *ptr++ = n; } *ptr = 0x00; Serial.println(target); return target; } void setup() { Serial.begin(115200); utf8rus("Testing"); utf8rus("Тест"); } void loop() { } выхлоп Testing : 0 : 0 : Testing Тест : 7 : 0 : ⸮⸮⸮⸮Вы думаете, что от замены
на
что-то поменялось? Таки нет. Если нужен массив, то и запрашивайте массив.
ничего не поменялось, кроме того что со скобками массив заполнен символами '\0', вопрос был каким образом он меняет свой размер
Никаким образом не меняет, это иллюзия.
strlen() бежит до первого встреченного '\0'. Таким образом у вас показывается не длина массива (размер выделенного фрагмента памяти), а расстояние от указателя target до ближайшего '\0'. Но так, как эта память ни от кого не защищена, то println() может внезапно показать 9000+ или вообще подвиснуть.
просто странно, если обьявляю так target[20]; то больше 20 символов не отображает, а так char* target = new char(); то отображает более 20 символов, вот и озадачился, что за х.....
Вот интересный вы человек. Поди в каком-нить приёмопередатчике антенну в силовую часть не бросите проводом, а тут пожалста - держите в незастолблённом куске памяти свои данные и удивляетсь.
так char* target = new char(); то отображает более 20 символов
При это запрашивает памяти на 1 (ОДИН) символ. А отображает сколько угодно, но из "свободной" памяти, которая может вполне себе оказать и не свободной, а занятой другими переменными. Здравствуйте, глюки!
Вы должны запрашивать столько помяти, сколько нужно.
Пока же, повторяю, Вы запрашиваете один байт, а пихаете туда "сколько придётся".
ЕвгенийП, я знаю что вы правы, просто было интересно, что в таком char target[20]; сразу видно что приплыл, а в таком char* target = new char(20); нет. Кто нибудь так и нарвется :)
просто было интересно, что в таком char target[20]; сразу видно что приплыл, а в таком char* target = new char(20); нет. Кто нибудь так и нарвется :)
Валера, похоже, вы этого не понимаете совсем.
b707, учиться, учиться, и учиться как сказал великий Ленин :)
А если так?
#define maxString 21 char target[maxString + 1] = ""; char *utf8rus(char *source) { int i,j,k; unsigned char n; char m[2] = { '0', '\0' }; strcpy(target, ""); k = strlen(source); i = j = 0; while (i < k) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } m[0] = n; strcat(target, m); j++; if (j >= maxString) break; } return target; }я думаю что лучше так, strcat тормознутая
#define str_utf_len 22 char target[str_utf_len + 1] = ""; char* utf8rus(char *source) { uint8_t i = 0, j = 0; unsigned char n; uint8_t k = strlen(source); memset(target, '\0', str_utf_len + 1); char* ptr = target; while (i < k ) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } *ptr++ = n; j++; if (j >= str_utf_len) break; } *ptr = 0x00; return target; }А зачем вы memset/strlen делаете, если strcat избегаете?