Varför fungerar inte ASCII hex för åäö i Linux kompilatorn (C++)?

Permalänk
Medlem

Varför fungerar inte ASCII hex för åäö i Linux kompilatorn (C++)?

Alltså om man skriver cout << '\x99'; istället måste jag skriva antingen "Ö" eller "\u00D6". Exempelvis '\x51' fungerar.

Permalänk
Medlem

För att kompilatorn använder unicode och inte ASCII?

Skickades från m.sweclockers.com

Visa signatur

"One is always considered mad, when one discovers something that others cannot grasp."
- Ed Wood

Permalänk
Medlem
Skrivet av Ferrat:

För att kompilatorn använder unicode och inte ASCII?

Skickades från m.sweclockers.com

Du får gärna förklara närmare och tipsa om en implementation som fungerar på både Windows och Linux.

Permalänk
Medlem

Kort svar: "\x99", i.e. hex 99, är inte värdet för "Ö" i någon av de vanliga teckenkodningarna – ASCII, EASCII Latin 1, eller UTF-8.

Långt svar:
ASCII är 7-bitars kod, och sträcker sig bara till hex 79 / decimal 127, och som namnet antyder har den bara de tecken som amerikanerna behöver, i.e. inga åäö:n. ASCII plus en åttonde bit (vilket sträcker sig till hex FF, dec 255) kallas Extended ASCII, och finns i många varianter beroende på språk och region. För att slippa bråka med olika EASCII varianter beroende på land används idag främst UTF-8, vilken är en teckenkodning som använder en till fyra bytes för att representera alla tecken i Unicode – en enda teckenuppsättning för alla språk.

Vi studerar hex 99 i olika kodningar:

I ASCII är hex 99 odefinierat, då definitionsmängden bara är [x0, x79].

I EASCII Latin 1, vilket är den utökade variant av ASCII som varit standard i norden, så är x99 en kontrollkod, och representeras visuellt med "™". Värdet för "Ö" är xD6.

UTF-8 är gjord för att vara bakåtkompatibel med ASCII och börjar även med sama tecken som Latin 1, men med lite annan kodning. Kodpunkten för "Ö" är likt Latin 1 nr D6 (betecknat U+00D6, \u00D6 i C), men representeras med "\xc3\x96" i hex pga. hur UTF-8 fungerar.

Efter lite sökande fann jag till slut även en kodning där x99 faktiskt motsvarar Ö! I just IBM850 kodningen, också känd som DOS Latin 1, är detta fallet. Jag skulle gissa på att din (E)ASCII referens kommer från DOS-tiden, och att du arbetar med denna förlegade kodning. Använd en en modern referens för UTF-8 så blir det nog mindre förvirrning ska du se.

Visa signatur

Arbets- / Spelstation: Arch Linux - Ryzen 5 3600 - RX 7900 XT - 32G DDR4
Server: Arch Linux - Core i5-10400F - 16G DDR4

Permalänk
Medlem

+1 på Bryals svar.

Som tillägg kommer det antagligen göra skillnad hur din/användarens terminal är inställd. I västländerna är en standard Linux-terminal vad jag vet numera inställd på UTF8. På Windows-sidan verkar det vara allmän förvirring där både cmd.exe och PowerShell verkar vara på gång att förändras, eller redan ha förändrats (man frångår windows-1252 och UCS-2). Användare kan förstås ändra inställningarna på sin terminal, både i Linux och på Windows!

Permalänk
Datavetare
Skrivet av jasm:

Du får gärna förklara närmare och tipsa om en implementation som fungerar på både Windows och Linux.

Första frågan: måste du använda C++? C++ har tyvärr inget enkelt sätt att hantera UTF-8 (än, det kommer förhoppningsvis...). Kan man locka med att titta på Go, där har man riktigt ordentligt tänkt igenom just hantering av strängar och UTF-8 används rakt igenom och uppför sig "som man förväntar sig att strängar ska uppföra sig".

Andra frågan: vad exakt vill du göra? Hantering av åäö är inget problem när man kör C/C++ i Linux, dock hanteras dessa tecken just som UTF-8 när de väl skrivs på konsolen. Windows använder fortfarande Latin1 för konsolapplikationer (vilket 2019 känns rätt mycket WTF!).

Tredje frågan: fungerar det inte att använda just åäö i stället för att använda hex-literaler (som då kräver att du känner till systemets text-kodningssystem)?

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av jasm:

Du får gärna förklara närmare och tipsa om en implementation som fungerar på både Windows och Linux.

Ett knep är att ha olika kodsegment för Windows och Linux och låta pre-processorn styra vilka segment som skall kompileras olika för respektive plattform.

Ett annat knep är att flytta all texthantering in-/ut-/test till en enda källkodsfil, eller möjligen en väl avgränsad grupp källkodsfiler. Och använda olika versioner av källkodsfilerna beroende på plattform.

Ytterligare ett knep är att i koden detektera vilken plattform programmet körs och ha input/output-filter som hanterar tecken korrekt för respektive plattform.

Ännu ett knep är att ha alla texter i externa textfiler. Olika för olika plattformar och språk. Kombineras lämpligen med detektering av plattform och ut-/in-filter samt konfigurationsfiler med språkval.

Till sist kan du kanske hålla dig till ren ASCII och göra allt på Engelska. Då slipper du bry dig. Lämpligt för små testprogram.

Visa signatur

Linux och Android

Permalänk
Medlem
Skrivet av jasm:

Alltså om man skriver cout << '\x99'; istället måste jag skriva antingen "Ö" eller "\u00D6". Exempelvis '\x51' fungerar.

Hmm.. Jag kan inte hitta att ostream::operator << (char) egentligen skulle fungera. Det verkar vara en GNU-utökning.
På andra system så borde char:en rimligtvis omvandlas till en short och istället tolkas som ett tal att skrivas ut i decimal form, vilket skulle bli ännu mer fel.

'\x99' hade blivit till en enstaka 'char' (alltså en byte) som åkte ut på terminalen. Om din terminal vore inställd på iso8859-1 (eller Windows utökade variant av det) så skulle det visas rätt tecken, men dagens Linuxsystem brukar vara förinställda på UTF-8 - enkodat Unicode.
UTF-8 är en kodning av heltal i sekvenser av 8-bittars bytes. Bit 7 i varje byte en speciell funktion: om den är satt så tolkas byte:n som en del av en multibyte-sekvens. Om bit 7 är 0 så används byte:n som den är.
Antal ettor efter den första (bit 6, 5, etc.) visar hur många bytes som ska komma efter den första. Sedan följer en nolla. I de efterföljande bytes:en måste bit 6 vara 0. Dagens terminaler brukar vara smarta nog att förstå felaktiga sekvenser och skriva ut ett tecken för det: �.

Exempel: Bokstaven "Ö" kodas som "\xC3\x96".
Eller binärt: 11000011-10010110. De understrukna bittarna är kontroll-bittar för tecknet av värde 000-11010110.

Visa signatur

För övrigt anser jag att tobak ska förbjudas.