staging.inyokaproject.org

[C++] Wie packe ich enkodierte Zeichen plattformunabhängig in einen const char[]?

Status: Gelöst | Ubuntu-Version: Ubuntu 20.04 (Focal Fossa)
Antworten |

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

Hallo,

ich versuche gerade ein VDR-Plugin für die ARM-Architekturen bauen zu lassen, bei dem der Author versucht hat einen non-breaking Space als nullterminierte UTF-8 und latin-1 encodierte Zeichen in einen Char-Array zu packen: vdr-projects/vdr-plugin-xmltv2vdr/blob/master/import.cpp.

Wenn ich das ganze für amd64 baue, klappt das, für ARM aber nicht (bzw. nur mit -std=c++03, was ich nicht will), da bekomme ich folgende Fehlermeldung (Buildlog):

import.cpp: In member function ‘char* cImport::AddEOT2Description(char*, bool)’:
import.cpp:264:37: error: narrowing conversion of ‘-62’ from ‘int’ to ‘char’ [-Wnarrowing]
  264 |     const char nbspUTF8[]={-62,-96,0};
      |                                     ^
import.cpp:264:37: error: narrowing conversion of ‘-96’ from ‘int’ to ‘char’ [-Wnarrowing]
import.cpp:280:41: error: narrowing conversion of ‘-96’ from ‘int’ to ‘char’ [-Wnarrowing]
  280 |                 const char nbsp[]={-96,0};
      |                                         ^
make[2]: *** [Makefile:70: import.o] Error 1

Das Problem entsteht wenn ich das richtig verstehe dadurch, dass char je nach Plattform signed bzw. unsigned ist.

In Python wäre das ja recht einfach die Bytes anzugeben: b'\xc2\xa0\x00' - darf man das in C++ so als String Literal hinterlegen?

1
2
3
4
5
6
7
#include <iostream>
int main() {
        const char nbspUTF8[]{"\u00A0\0}"};    // nbsp für UTF-8
        const char nbsp[]{"\240\0"};           // nbsp für latin-1
        std::cout << "'" << nbspUTF8 << "'\n";
        std::cout << "'" << nbsp << "'\n";
}

Ist das ein guter Weg (zumindest akzeptiert das der Compiler auf einem armv7h und einem amd64 System so ohne zu meckern und laut xxd kommt das gleiche raus) und gibt es da noch andere empfehlenswerte Möglichkeiten das umzusetzen?

NORACSA

Anmeldungsdatum:
31. Januar 2010

Beiträge: 182

Mit u8 vor dem String kannst du ihn als UTF8 String deklarieren! Und das \0 am Ende des Strings ist auch unnötig.

seahawk1986

(Themenstarter)

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

NORACSA schrieb:

Mit u8 vor dem String kannst du ihn als UTF8 String deklarieren!

Dann müsste ich dann aber ein geschütztes Leerzeichen in den Code schreiben und darauf hoffen, dass jeder, der die Datei in Zukunft bearbeitet UTF-8 nutzt, oder?

Und das \0 am Ende des Strings ist auch unnötig.

Dann war es das auch schon im ursprünglichen Code überflüssig, oder?

NORACSA

Anmeldungsdatum:
31. Januar 2010

Beiträge: 182

seahawk1986 schrieb:

NORACSA schrieb:

Mit u8 vor dem String kannst du ihn als UTF8 String deklarieren!

Dann müsste ich dann aber ein geschütztes Leerzeichen in den Code schreiben und darauf hoffen, dass jeder, der die Datei in Zukunft bearbeitet UTF-8 nutzt, oder?

Am geschicktesten ist es wohl, wenn du auch dann u8"This is a Unicode Character: \u2018." schreibst! ☺

seahawk1986 schrieb:

NORACSA schrieb:

Und das \0 am Ende des Strings ist auch unnötig.

Dann war es das auch schon im ursprünglichen Code überflüssig, oder?

Wenn der ursprüngliche Code const char nbspUTF8[]={-62,-96,0}; war, dann wohl nicht, weil du ja hier keine Zeichenkette initialisierst sondern die einzelnen Elemente eines Arrays. Das sind zwei verschiedene Sachen.

seahawk1986

(Themenstarter)

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

NORACSA schrieb:

Am geschicktesten ist es wohl, wenn du auch dann u8"This is a Unicode Character: \u2018." schreibst! ☺

Laut dem Compiler Explorer bekomme ich dann aber wieder ab C++20 Probleme ( https://en.cppreference.com/w/cpp/language/character_literal, Erklärung der zweiten Form), weil er dann einen char8_t zu einem char umwandeln müsste:

error: cannot initialize array of 'char' from a string literal with type array of 'char8_t'

Und die Workarounds, die in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1423r3.html diskutiert werden, sehen für mich komplizierter aus als das u8 vor dem String wegzulassen (wobei mir noch nicht klar ist, ob das unerwünschte Nebenwirkungen haben kann).

NORACSA schrieb:

Wenn der ursprüngliche Code const char nbspUTF8[]={-62,-96,0}; war, dann wohl nicht, weil du ja hier keine Zeichenkette initialisierst sondern die einzelnen Elemente eines Arrays. Das sind zwei verschiedene Sachen.

Ah stimmt, zwischen "\240" und '\240' gibt es ja in C(++) einen Unterschied - danke, ich glaube ich geh erst mal eine Runde schlafen 😫

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

seahawk1986 schrieb:

…gibt es da noch andere empfehlenswerte Möglichkeiten das umzusetzen?

Beim Arduino wird das mit dem Typ byte gemacht, was nichts anderes ist als ein unsigned char. Dadurch ist der auf jeder Plattform gleich, weil separat definiert.

Auch wichtig ist darauf zu achten, wo der char signed sein MUSS, wenn er bspw. als counter, errorcode (return -1) oder dergleichen verwendet wird. Da muss man das auch explizit davorschreiben, sonst kommt bspw. auf Raspi oder Handy mit ARM nur Murks raus.

Antworten |