Programing

유니 코드 what ()의 예외

crosscheck 2020. 12. 31. 22:51
반응형

유니 코드 what ()의 예외


또는 "러시아인은 어떻게 예외를 던지나요?"

std :: exception의 정의는 다음과 같습니다.

namespace std {
  class exception {
  public:
    exception() throw();
    exception(const exception&) throw();
    exception& operator=(const exception&) throw();
    virtual ~exception() throw();
    virtual const char* what() const throw();
  };
}

예외 계층 구조를 설계 하는 데 널리 사용되는 생각 은 std :: exception에서 파생하는 것입니다.

일반적으로 내장 된 개체가 아닌 개체를 던지는 것이 가장 좋습니다. 가능하다면 std :: exception 클래스에서 (궁극적으로) 파생되는 클래스의 인스턴스를 던져야합니다. 예외 클래스가 표준 예외 기본 클래스에서 (궁극적으로) 상속되도록함으로써 사용자의 삶을 더 쉽게 만들고 (표준 :: exception을 통해 대부분의 것을 포착 할 수있는 옵션이 있음) 추가 정보를 제공 할 수 있습니다. (예를 들어, 특정 예외가 std :: runtime_error 등의 구체화 일 수 있다는 사실) .std :: runtime_error 등).

그러나 유니 코드를 보면 다음 두 가지를 모두 달성하는 예외 계층 구조를 설계하는 것은 불가능 해 보입니다.

  • 캐치 사이트에서의 사용 용이성을 위해 궁극적으로 std :: exception에서 파생됩니다.
  • 유니 코드 호환성을 제공하여 진단이 분리되거나 횡설수설하지 않습니다.

유니 코드 문자열로 구성 할 수있는 예외 클래스를 만드는 것은 충분히 간단합니다. 그러나 표준에 따르면 what ()은 const char *를 반환해야하므로 어떤 시점에서 입력 문자열은 ASCII로 변환되어야합니다. 생성시 또는 what ()이 호출 될 때 수행되는지 여부 (소스 문자열이 7 비트 ASCII로 표현할 수없는 문자를 사용하는 경우) 충실도를 잃지 않고 메시지를 형식화하는 것이 불가능할 수 있습니다.

std :: exception 파생 클래스의 원활한 통합과 무손실 유니 코드 진단을 결합하는 예외 계층을 어떻게 설계합니까?


char *는 ASCII를 의미하지 않습니다. UTF-8과 같은 8 비트 유니 코드 인코딩을 사용할 수 있습니다. char은 16 비트 이상일 수도 있으며 UTF-16을 사용할 수 있습니다.


UTF-8 반환은 당연한 선택입니다. 예외를 사용하는 응용 프로그램이 다른 멀티 바이트 인코딩을 사용하는 경우 문자열을 표시하는 데 어려움이있을 수 있습니다. (UTF-8인지 알 수 없습니까?) 반면에 ISO-8859- * 8 비트 인코딩 (서유럽 어, 키릴 문자 등)의 경우 UTF-8 문자열을 표시하면 "그냥"일부 횡설수설이 표시됩니다. 그리고 btw를 명확하게 할 수 없다면 당신 (또는 당신의 사용자)이 괜찮을 수 있습니다. 로케일 문자 세트 및 UTF-8의 char *.

개인적으로 저는 저수준 오류 메시지 만 what () 문자열에 들어가야한다고 생각하며 개인적으로 이것들은 어쨌든 영어 여야한다고 생각합니다. (일부 오류 번호 또는 기타와 결합 될 수 있습니다.)

내가 보는 최악의 문제 what()는 what () 메시지에 상황에 맞는 세부 정보 (예 : filename )를 포함하는 것이 드물지 않다는 것입니다 . 파일 이름은 당신은 선택의 여지가 남아 있습니다 만으로 UTF-8을 사용하기 때문에, 오히려 종종 ASCII what()인코딩.

예외 클래스 (std :: exception에서 파생 됨)는 분명히 원하는 모든 액세스 방법을 제공 할 수 있으므로 명시 적 what_utf8()또는 what_utf16()또는 을 추가하는 것이 합리적 일 수 있습니다 what_iso8859_5().

편집 : UTF-8을 반환하는 방법에 대한 John의 의견에 관하여 :

const char* what()함수 가있는 경우이 함수는 기본적으로 여러 바이트를 반환합니다. 서부 유럽 Windows 플랫폼에서,이 바이트는 일반적으로 인코딩 될 Win1252 하지만, 러시아어 창에 그것은뿐만 아니라 수 있습니다 Win1251 .

반환되는 바이트의 의미는 인코딩에 따라 다르며 인코딩은 "원래"(그리고이를 해석하는 사람)에 따라 다릅니다. 문자열 리터럴의 인코딩은 컴파일 타임에 정의되지만 런타임에이를 해석하는 방법은 여전히 ​​애플리케이션에 달려 있습니다.

따라서 예외가 what()(또는 what_utf8())을 사용 하여 UTF-8 문자열을 반환 하도록하려면 다음을 확인해야합니다.

  • 예외에 대한 입력 메시지에 잘 정의 된 인코딩이 있습니다.
  • 메시지를 보관하는 데 사용하는 문자열 멤버에 대해 잘 정의 된 인코딩이 있습니다.
  • what()호출 하면 인코딩을 적절하게 변환합니다.

예:

struct MyExc : virtual public std::exception {
  MyExc(const char* msg)
  : exception(msg)
  { }
  std::string what_utf8() {
    return convert_iso8859_1_to_utf8( what() );
  }
};

// In a ISO-8859-1 encoded source file
const char* my_err_msg = "ISO-8859-1 ... äöüß ...";
...
throw MyExc(my_err_msg);
...
catch(MyExc const& e) {
  std::string iso8859_1_msg = e.what();
  std::string utf_msg = e.what_utf8();
...

변환은 MyExc ()의 (무시 된) what () 멤버 함수에 배치 되거나 이미 UTF-8로 인코딩 된 문자열을 사용하도록 예외를 정의 하거나 예상 된 입력 인코딩에서 wchar_t / UTF로 변환 할 수 있습니다. -16) ctor에서.


첫 번째 질문은 what () 문자열로 무엇을 하시겠습니까?

정보를 어딘가에 기록 할 계획입니까?

If so you should not be using the content of the what() string you should be using that string as a reference to look up the correct local specific logging message. So to me the content of the what() is not for logging purposes (or any form of display) it is a method of looking up the actual logging string (which can be any Unicode string).

Now; It can be us-full for the what() string to contain a human readable message for the developers to help in quick debugging (but for this highly readable polished text is not required). As result there is no reason to support anything more than ASCII. Obey the KISS principle.


A const char* doesn't have to point to an ASCII string; it can be in a multi-byte encoding such as UTF-8. One option is to use wcstombs() and friends to convert wstrings to strings, but you may have to convert the result of what() back to wstring before printing. It also involves more copying and memory allocation than you may be comfortable with in an exception handler.

I usually just define my own base exception class, which uses wstring instead of string in the constructor and returns a const wstring& from what(). It's not that big of a deal. The lack of a standard one is a pretty big oversight.

Another valid opinion is that exception strings should never be presented to the user, so localizing them isn't necessary and so you don't have to worry about any of the above.


Standard doesn't specify what encoding is the string returned by what(), neither there is any defacto standard. I just encode it as UTF-8 and return from what(), in my projects. Of course there may be incompatibility with other libraries.

See also: https://stackoverflow.com/questions/1049947/should-utf-16-be-considered-harmful for why UTF-8 is good choice.


The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) by Joel Spolsky

Edit: Made CW, commenters may edit in why this link is relevant if they wish


It is better way to add unicode in error processing:

try
{
   // some code
}
catch (std::exception & ex)
{
    report_problem(ex.what())
}

And :

void report_problem(char const * const)
{
   // here we can convert char to wchar_t or do some more else
   // log it, save to file or message to user
}

what() is generally not meant to display a message to a user. Among other things the text it returns is not localizable (even if it was Unicode). I'd just use what() to display something of value to you as the developer (like the source file and line number of the place where the exception was raised) and for that sort of text, ASCII is usually more than enough.

ReferenceURL : https://stackoverflow.com/questions/3760731/exceptions-with-unicode-what

반응형