Linux(및 Unix?)의 C++에서 가장 일반적인 문자열 인코딩

Linux(및 Unix?)의 C++에서 가장 일반적인 문자열 인코딩

Windows와 Linux 간에 이식 가능한 소스 코드 수준이고 국제화를 잘 처리하는 C++ 프로그램을 만들려면 IMHO에서 고려해야 할 세 가지 주요 인코딩이 있습니다.

  • C++ 소스 코드 인코딩.
  • 외부 데이터 인코딩.
  • 문자열과 리터럴의 인코딩.

C++ 소스 코드의 경우, 적어도 표준 입력 및 와이드 문자열 리터럴이 Windows 플랫폼에서 작동해야 한다면 BOM이 있는 UTF-8을 대체할 수 있는 방법은 없습니다. BOM이 없는 UTF-8을 사용하면 Microsoft의 Visual C++ 컴파일러가 소스 코드의 Windows ANSI 인코딩을 채택하게 됩니다. 이는 UTF-8을 통한 출력에는 적합 std::cout하지만 제한된 범위에서만 작동합니다(Windows 콘솔 창에는 버그가 있습니다). 그러나 via를 입력하면 std::cin작동하지 않습니다.

외부 데이터의 경우 UTF-8은 다음과 같습니다.이것사실상 표준.

하지만 내부 리터럴과 문자열은 어떻습니까? 여기 있어요인상UTF-8로 좁은 문자열 인코딩은 Linux에서 일반적인 규칙입니다. 그러나 최근 두 사람이 서로 다른 주장을 했습니다. 한 사람은 Linux의 국제 응용 프로그램에서 내부 문자열에 대한 보편적인 규칙이 UTF-32라고 주장하고, 다른 한 사람은 단순히 이 점에서 Unix와 Linux 사이에 불특정 차이점이 있다고 주장합니다.

이 분야의 Windows/Linux 차이점을 추상화하는 작은 라이브러리를 취미로 조금 수정하는 사람으로서 저는...구체적인 문의사항

  • 프로그램에서 문자열을 표현하기 위한 일반적인 Linux 규칙은 무엇입니까?

나는 이 질문™에 대한 실제 답변이 있을 정도로 매우 흔한 공통 규칙이 있다고 확신합니다.

Linux 방식으로 문자열을 뒤집는 방법을 보여주는 예(UTF-8을 직접 사용하면 복잡하지만 Linux의 사실상 표준 함수를 통해 수행되는 것으로 추정됨)도 좋습니다. 즉, 질문으로 이 C++ Linux 일반 버전은 무엇입니까? 프로그램(주어진 코드는 C++ 좁은 텍스트 실행 문자 집합인 Latin-1에 대한 것입니다):

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

#define STATIC_ASSERT( cond )   static_assert( cond, #cond )

int main()
{
    string line;
    if( getline( cin, line ) )
    {
        static char const aSingleChar[] = "æ";
        STATIC_ASSERT( sizeof( aSingleChar ) - 1 == 1 );
        reverse( line.begin(), line.end() );

        cout << line << endl;
    }
}

답변1

귀하의 질문이 상당히 광범위하기 때문에 이는 부분적인 답변일 뿐입니다.

C++에서는 "실행 문자 집합"을 정의합니다(실제로는 좁은 문자 집합과 넓은 문자 집합 두 개가 있습니다).

소스 파일에 다음이 포함된 경우:

char s[] = "Hello";

그런 다음 수행된 인코딩을 기반으로 문자열 리터럴에서 문자의 숫자 바이트 값을 찾으십시오. (홀로넓은와이드 문자 상수에 할당된 숫자 값에는 적용 인코딩이 적용됩니다 L'a'. )

이 모든 작업은 컴파일 프로세스에서 소스 코드 파일을 처음 읽는 과정의 일부로 발생합니다. 내부에 들어가면 C++ 문자는 추가 의미가 없는 바이트일 뿐입니다. (유형 이름은 charC 파생 언어에서 최악의 잘못된 이름 중 하나임에 틀림없습니다!)

C++11에는 리터럴 u8""u""OK 가 있는 부분적인 예외가 있습니다.U""결과문자열 요소의 값(즉, 결과 값은 전역적으로 명시적이고 플랫폼 독립적임)이지만 이는 영향을 미치지 않습니다.소스코드를 입력하세요설명될 것입니다.

좋은 컴파일러는 다음을 허용해야 합니다.지정하다소스 코드는 인코딩되어 있으므로 친구가 EBCDIC 시스템에서 프로그램 텍스트를 보내더라도 문제가 되지 않습니다. GCC는 다음과 같은 옵션을 제공합니다:

  • -finput-charset: 입력 문자 집합, 즉 소스 코드 파일이 인코딩되는 방식
  • -fexec-charset: 실행 문자 집합, 즉 문자열 리터럴이 인코딩되는 방식
  • -fwide-exec-charset: 넓은 실행 문자 집합, 즉 넓은 문자열 리터럴을 인코딩하는 방법

변환 에는 GCC가 사용되므로 iconv()지원되는 모든 인코딩을 iconv()이러한 옵션과 함께 사용할 수 있습니다.

이전에 쓴C++ 표준은 텍스트 인코딩을 처리하기 위한 몇 가지 불투명 도구를 제공합니다.


예: char s[] = "Hello";소스 파일이 ASCII(예:코드를 입력ASCII입니다). 그런 다음 컴파일러는 이를 읽고 99해석하는 c등의 작업을 수행합니다. 문자 그대로의 의미로 보면 72이라고 읽고 해석한다 H. 이제 수행된 인코딩( ASCII 또는 UTF-8인 경우) H에 의해 결정된 바이트 값을 배열에 저장합니다 . 72를 쓰면 \xFF컴파일러는 이를 읽고 99 120 70 70, 디코딩하고 , 배열 \xFF에 씁니다 .255

답변2

외부 표현의 경우 UTF-8이 확실히 표준입니다. 일부 8비트 인코딩은 여전히 ​​강력하고(주로 유럽에서) 일부 16비트 인코딩은 여전히 ​​강력하지만(주로 동아시아에서) 천천히 종료되고 있는 레거시 인코딩임이 분명합니다. UTF-8은 UNIX 표준일 뿐만 아니라 웹 표준이기도 합니다.

내부 표현에 있어서 그렇게 압도적인 기준은 없습니다. 주위를 둘러보면 일부 UTF-8, 일부 UCS-2, 일부 UTF-16 및 일부 UCS-4를 찾을 수 있습니다.

  • UTF-8의 장점은 범용 표현과 일치하고 ASCII의 상위 집합이라는 것입니다. 특히 널 문자가 널 바이트에 해당하는 유일한 인코딩입니다. 이는 C API(UNIX 시스템 호출 및 표준 라이브러리 함수 포함)가 있는 경우 중요합니다.
  • UCS-2는 역사의 유물입니다. 고정폭 인코딩으로 간주되기 때문에 매력적이지만, 유니코드 전체를 나타내지 않는다는 점이 방해가 됩니다.
  • UTF-16의 주요 평판은 Java 및 Windows API에 있습니다. Unix용으로 프로그래밍하는 경우 Unix API(예: UTF-8)가 Windows API보다 더 적합합니다. UTF-16과 같은 API와 상호 작용하도록 설계된 프로그램만 UTF-16을 사용하는 경향이 있습니다.
  • UCS-4는 고정 너비 인코딩처럼 보이기 때문에 매력적입니다. 문제는 그렇지 않다는 것입니다. 문자 조합으로 인해 고정 너비 유니코드 인코딩이 없습니다.
  • 게다가 wchar_t. 문제는 일부 플랫폼에서는 2바이트이고 다른 플랫폼에서는 4바이트이며 그것이 나타내는 문자 집합이 지정되지 않는다는 것입니다. 유니코드가 사실상의 표준 문자 집합이 되면서 새로운 응용 프로그램은 기피되는 경향이 있습니다 wchar_t.

UNIX 세계에서 가장 중요한 인수는 일반적으로 UTF-8을 가리키는 UNIX API와의 호환성입니다. 그러나 보편적이지 않기 때문에 라이브러리가 다른 인코딩을 지원해야 하는지 여부에 대한 예 또는 아니요 대답은 없습니다.

이와 관련하여 유닉스 변형 간에는 차이가 없습니다.Mac OS X은 분해 문자를 선호합니다.정규화된 표현을 얻으려면 그렇게 하고 싶을 수도 있습니다. OSX에서는 일부 작업이 절약되지만 다른 unice에서는 중요하지 않습니다.

UTF-8에는 BOM과 같은 것이 없습니다. 바이트 순서 표시는 슈퍼바이트 크기 인코딩에만 의미가 있습니다. UTF-8로 인코딩된 파일이 U+FEFF 문자로 시작해야 한다는 요구 사항은 일부 Microsoft 응용 프로그램에만 적용됩니다.

답변3

어떤 사람들은 Linux 국제 응용 프로그램의 내부 문자열에 대한 보편적인 규칙이 UTF-32라고 주장합니다.

이는 = UTF-16(Windows와의 호환성을 위해)을 정의하는 Windows C(++) 컴파일러와 달리 wchar_tGCC가 문자를 UTF-32로 정의한다는 사실을 나타낼 수 있습니다 .wchar_tWCHAR

할 수 있다wchar_t편리한 경우 내부적으로 사용할 수 있습니다. 그러나 POSIX API는 Windows와 같은 와이드 문자를 사용하도록 다시 작성되지 않았기 때문에 *nix 세계에서는 Windows 세계만큼 일반적이지 않습니다.

UTF-8을 내부적으로 사용하면 "중립 인코딩" 루틴에 적합합니다. 예를 들어, 탭으로 구분된 스프레드시트를 CSV로 변환하는 프로그램을 생각해 보세요. ASCII 문자 \t, ,, 및 특별히 처리해야 "하지만 ASCII가 아닌 범위의 모든 바이트(ISO-8859-1 문자 또는 UTF-8 코드 단위를 나타내는지 여부)는 그대로 복사할 수 있습니다.

취미로 이 영역의 Windows/Linux 차이점을 추상화하도록 설계된 작은 라이브러리를 사용하여 약간의 작업을 하고 있는 사람으로서,

크로스 플랫폼 코드를 작성할 때의 많은 성가심 중 하나는 Windows에서는 UTF-16을 사용하기 쉽고 UTF-8은 사용하기 어렵다는 것입니다. 그러나 Linux에서는 그 반대의 경우도 마찬가지입니다. 다음과 같은 함수를 작성하여 처리합니다.

FILE* fopen_utf8(const char* filename, const char* mode)
{
#ifdef _WIN32
    std::wstring wfilename = ConvertUtf8ToUtf16(filename);
    std::wstring wmode = ConvertUtf8ToUtf16(mode);
    return _wfopen(wfilename.c_str(), wmode.c_str());
#else
    return fopen(filename, mode);
#endif
}

관련 정보