(1) O que significa sequência de bytes, um array de char em C? O UTF-16 é uma sequência de bytes ou o que é então? (2) Por que uma sequência de bytes não tem nada a ver com comprimento variável?
Você parece estar entendendo mal quais são os problemas endian. Aqui está um breve resumo.
Um número inteiro de 32 bits ocupa 4 bytes. Agora, sabemos a ordem lógica desses bytes. Se você tiver um número inteiro de 32 bits, poderá obter o byte mais alto com o seguinte código:
uint32_t value = 0x8100FF32;
uint8_t highByte = (uint8_t)((value >> 24) & 0xFF); //Now contains 0x81
Está tudo bem e bem. Onde o problema começa é como várias ferragens armazenam e recuperam números inteiros da memória.
Na ordem Big Endian, uma parte de 4 bytes de memória que você lê como um número inteiro de 32 bits será lida com o primeiro byte sendo o byte alto:
[0][1][2][3]
Na ordem Little Endian, uma parte de 4 bytes de memória que você lê como um número inteiro de 32 bits será lida com o primeiro byte sendo o byte baixo :
[3][2][1][0]
Se você tiver um ponteiro para um ponteiro para um valor de 32 bits, poderá fazer o seguinte:
uint32_t value = 0x8100FF32;
uint32_t *pValue = &value;
uint8_t *pHighByte = (uint8_t*)pValue;
uint8_t highByte = pHighByte[0]; //Now contains... ?
De acordo com C / C ++, o resultado disso é indefinido. Pode ser 0x81. Ou pode ser 0x32. Tecnicamente, ele pode retornar qualquer coisa, mas, para sistemas reais, ele retornará um ou outro.
Se você tiver um ponteiro para um endereço de memória, poderá lê-lo como um valor de 32 bits, um valor de 16 bits ou um valor de 8 bits. Em uma grande máquina endian, o ponteiro aponta para o byte alto; em uma pequena máquina endian, o ponteiro aponta para o byte baixo.
Observe que isso é tudo sobre leitura e gravação de / para a memória. Não tem nada a ver com o código C / C ++ interno. A primeira versão do código, aquela que o C / C ++ não declara indefinida, sempre funcionará para obter o byte alto.
O problema é quando você começa a ler fluxos de bytes. Como de um arquivo.
Valores de 16 bits têm os mesmos problemas que os de 32 bits; eles têm apenas 2 bytes em vez de 4. Portanto, um arquivo pode conter valores de 16 bits armazenados em big endian ou little endian order.
UTF-16 é definido como uma sequência de valores de 16 bits . Efetivamente, é um uint16_t[]
. Cada unidade de código individual é um valor de 16 bits. Portanto, para carregar o UTF-16 corretamente, você deve saber qual é a capacidade de endereçamento dos dados.
UTF-8 é definido como uma sequência de valores de 8 bits . É um uint8_t[]
. Cada unidade de código individual tem 8 bits de tamanho: um único byte.
Agora, UTF-16 e UTF-8 permitem que várias unidades de código (valores de 16 ou 8 bits) se combinem para formar um ponto de código Unicode (um "caractere", mas esse não é o termo correto; é uma simplificação ) A ordem dessas unidades de código que formam um ponto de código é ditada pelas codificações UTF-16 e UTF-8.
Ao processar UTF-16, você lê um valor de 16 bits, fazendo a conversão endian necessária. Em seguida, você detecta se é um par substituto; se for, você lê outro valor de 16 bits, combina os dois e, a partir disso, obtém o valor do ponto de código Unicode.
Ao processar UTF-8, você lê um valor de 8 bits. Nenhuma conversão endian é possível, pois há apenas um byte. Se o primeiro byte denota uma sequência de vários bytes, você lê algum número de bytes, conforme determinado pela sequência de vários bytes. Cada byte individual é um byte e, portanto, não possui conversão endian. A ordem desses bytes na sequência, assim como a ordem dos pares substitutos em UTF-16, é definida por UTF-8.
Portanto, não pode haver problemas endian com o UTF-8.