在向我的arduino发送一些uft8编码的字符串时,我遇到了一些奇怪的行为。我开始使用this示例并对其进行了修改。我的程序如下:
我正在根据示例监听SerialEvent。通过这种方式,我不是在字符串中添加字符,而是以循环方式添加到char [500]数组中。有两个指针变量,一个用于读取,一个用于写入,它们都递增到499然后再设置为0.
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
if (inChar != '\r') {
if (inChar == '\n') {
commandsInQueue++;
inChar = NULL;
}
inputBuffer[ptrInputWrite] = inChar;
if (ptrInputWrite < 499) ptrInputWrite++; else ptrInputWrite = 0;
}
}
}
然后在循环函数内部有一个读者。在那里,它从该数组创建一个String,并通过引用将其交给解码器函数。在那里,我使用String的indexOf函数将命令拆分为它的部分。
if (commandsInQueue > 0) {
String tmp = "";
tmp.reserve(500);
do {
tmp += inputBuffer[ptrInputRead];
if (ptrInputRead < 499) ptrInputRead++; else ptrInputRead = 0;
} while (inputBuffer[ptrInputRead] != NULL);
rxInterpreter(tmp);
if (ptrInputRead < 499) ptrInputRead++; else ptrInputRead = 0;
commandsInQueue--;
}
解码器:
void rxInterpreter(String cmd) {
unsigned int lastSem = 2, nextSem = NULL;
Serial.println("Processing command: " + cmd);
if (connectionOpen) {
switch (cmd[0])
{
// ...
case 'T':
textRefreshTime = millis();
refreshBar = true;
currentPos = 0;
displayShift = 0;
currentlyShowing = 0;
{
unsigned short len = cmd.length();
for (short i = 0; i < len; i++) {
if ((unsigned long)cmd[i] > 255) {
unsigned long chr = (unsigned short)cmd[i] << 8 | (byte)cmd[i + 1];
switch (chr) {
case 0xc384: //Ä
case 0xc3a4: //ä
cmd[i] = (uint8_t)B11100001; break;
case 0xc396: //Ö
case 0xc3b6: //ö
cmd[i] = (uint8_t)B11101111; break;
case 0xc39c: //Ü
case 0xc3bc: //ü
cmd[i] = (uint8_t)B11110101; break;
case 0xc39f: //ß
cmd[i] = (uint8_t)B11100010; break;
default:
Serial.println("Unbekanntes Zeichen " + String(chr, HEX));
}
cmd.remove(i + 1, 1);
len--;
}
}
}
// ...
该过程的一部分是解释utf8:我的第一种方法是通过检查当前char的值是否大于0xC0来查找utf8字符的bit signature。这没用。经过一番研究后,我意识到,由于某种原因,从该位置返回的字符不是8,而是16位长。所以cmdString [i]通常会返回一个字节,但是如果该字符是一个uft8字符,那么它将返回连续的签名短路,其中上面的两个八位字节用1填充。
例如变音符号(ä),其utf8代码为0xc3a4。我希望cmdString [i]为0xc3,cmdString [i + 1]为0xa4。但是,实际上,[i]返回0xffc3(十进制为-61)和[i + 1] 0xffa4(十进制为-92)。因为它将这些值解释为有符号变量,所以检查它们是否大于0xc0会自然失败。
我通过打印Serial.println(String(cmdString[i], HEX));
来测试它。 BINARY
。它总是返回4/16位数,而不是2/8。
有人可以向我解释,为什么会这样?它与我(分别是arduino库)从字节数组创建字符串对象的方式有关吗?我一直认为,char在所有情况下都是无符号字节。我发现这甚至是一个错误吗?
我已经在我的代码中解决了这个问题。但我仍然想知道为什么会这样。
答案 0 :(得分:1)
你可能遇到了C语言的一些怪癖(C ++并没有真正参与其中,它继承了这些规则)。
char
类型与signed char
和unsigned char
不同,并且已实现定义普通char
是否可以具有负值(如果是, 哪一个)。显然,您的系统允许-91
。
第二个怪癖是char
类型的表达式经常被提升为int
,例如当您比较((char)0xC0) < 0
时,右侧为0
,int
,因此左侧也会提升为int
。
这不是UTF-8特有的。 ISO-8859-x也存在同样的问题。