2012-10-24 39 views
21

Các chức năng c32rtombmbrtoc32 từ <cuchar>/<uchar.h> được mô tả trong thư mục C Unicode TR (draft) như thực hiện chuyển đổi giữa UTF-32 và "ký tự nhiều byte".Mã hóa nào c32rtomb chuyển đổi thành?

(...) Nếu s không phải là một null con trỏ, các c32rtomb chức năng xác định số byte cần thiết để đại diện cho các ký tự multibyte tương ứng với nhân vật rộng do c32 (bao gồm bất kỳ sự thay đổi trình tự), và lưu trữ biểu diễn ký tự nhiều byte trong mảng có phần tử đầu tiên được trỏ đến bởi s. (...)

"Biểu diễn nhân vật đa byte" này là gì? Tôi thực sự quan tâm đến hành vi của các chương trình sau đây:

#include <cassert> 
#include <cuchar> 
#include <string> 

int main() { 
    std::u32string u32 = U"this is a wide string"; 
    std::string narrow = "this is a wide string"; 
    std::string converted(1000, '\0'); 
    char* ptr = &converted[0]; 
    std::mbstate_t state {}; 
    for(auto u : u32) { 
     ptr += std::c32rtomb(ptr, u, &state); 
    } 
    converted.resize(ptr - &converted[0]); 
    assert(converted == narrow); 
} 

là sự khẳng định trong đó đảm bảo để giữ ?


Làm việc theo giả định rằng __STDC_UTF_32__ được định nghĩa.

Trả lời

10

Để xác nhận được đảm bảo đúng, cần mã hóa nhiều byte được sử dụng bởi c32rtomb() giống như mã hóa được sử dụng cho chuỗi ký tự, ít nhất là các ký tự thực sự được sử dụng trong chuỗi.

C99 7.11.1.1/2 chỉ định rằng setlocale() với danh mục LC_CTYPE ảnh hưởng đến hành vi của các chức năng xử lý ký tự và chức năng nhiều byte và ký tự rộng. Tôi không thấy bất kỳ sự thừa nhận rõ ràng nào rằng hiệu ứng là để thiết lập các bảng mã ký tự nhiều byte và ký tự rộng được sử dụng, tuy nhiên đó là ý định.

Vì vậy, mã hóa nhiều byte được sử dụng bởi c32rtomb() là mã hóa nhiều byte từ ngôn ngữ mặc định "C".

C++ 11 2.14.3/2 chỉ định rằng mã hóa thực thi, mã hóa thực thi rộng, UTF-16 và UTF-32 được sử dụng cho ký tự và chuỗi ký tự tương ứng.Do đó std::string narrow sử dụng mã hóa thực thi để biểu diễn chuỗi đó.

Vậy mã hóa ngôn ngữ "C" của chuỗi này giống với mã hóa thực thi của chuỗi này?

C99 7.11.1.1/3 chỉ định rằng ngôn ngữ "C" cung cấp "môi trường tối thiểu" cho bản dịch C. Môi trường như vậy sẽ bao gồm không chỉ các bộ ký tự, mà còn bao gồm các mã ký tự cụ thể được sử dụng. Vì vậy, tôi tin rằng điều này có nghĩa không chỉ là miền địa phương "C" phải hỗ trợ các ký tự cần thiết trong bản dịch (nghĩa là bộ ký tự cơ bản), mà còn thêm các ký tự đó trong ngôn ngữ "C" phải sử dụng cùng một mã ký tự.

Tất cả các nhân vật trong xâu của bạn là thành viên của bộ ký tự cơ bản, và do đó chuyển đổi char32_t đại diện cho "C" đại diện char locale phải xuất trình cùng một chuỗi các giá trị như trình biên dịch tạo ra cho char chuỗi chữ ; xác nhận phải đúng.

Tôi không thấy bất kỳ đề xuất nào vượt quá bộ ký tự cơ bản được hỗ trợ theo cách tương thích giữa mã hóa thực thi và ngôn ngữ "C", vì vậy nếu chuỗi ký tự của bạn sử dụng bất kỳ ký tự nào bên ngoài bộ ký tự cơ bản thì sẽ không được đảm bảo rằng sự khẳng định sẽ giữ. Thậm chí quy định các ký tự mở rộng tồn tại trong cả bộ ký tự thực hiện và miền địa phương "C", tôi không thấy bất kỳ yêu cầu nào về các biểu diễn khớp với nhau.

+0

Câu trả lời hay. Chỉ cần được rõ ràng: Nếu anh ta thêm một cuộc gọi đến 'setlocale', xác nhận có thể thất bại, ngay cả khi các chuỗi của anh ta hoàn toàn nằm trong bộ ký tự cơ bản? – Nemo

+1

@Nemo Nếu 'setlocale()' được gọi với một đối số khác với '" C "', vâng. Ví dụ 'setlocale (" en_US.EBCDIC ")' (giả sử đó là một miền địa phương được hỗ trợ với ý nghĩa rõ ràng) trên một hệ thống nơi mã hóa thực thi tương thích ASCII sẽ gây ra 'c32rtomb()' để tạo ra các chuỗi EBCDIC trong khi 'std :: string hẹp' sẽ vẫn được mã hóa ASCII. – bames53

5

Các TR liên kết trong câu hỏi nói

Tại hầu hết các MB_CUR_MAX byte được lưu trữ.

được định nghĩa (trong C99) như

một biểu thức số nguyên dương với kiểu size_t đó là số lượng tối đa byte trong một ký tự multibyte cho bộ ký tự mở rộng theo quy định của địa phương hiện tại

Tôi tin rằng đây là bằng chứng đầy đủ rằng mục đích của TR là tạo ra các ký tự nhiều byte như được xác định bởi ngôn ngữ C hiện đang được cài đặt: UTF-8 cho en_US.utf8, GB18030 cho zh_CN.gb18030, et c)

0

Như tôi đã thử nghiệm, trong Linux/MacOSX, c32rtomb chuyển đổi chuỗi từ UTF-32 sang mã hóa cụ thể theo ngôn ngữ. Bạn có thể sử dụng nl_langinfo (CODESET) để nhận mã hóa hiện đang được sử dụng.

Tuy nhiên, libc sử dụng ngôn ngữ "C" theo mặc định, sử dụng mã hóa ISO-8859-1. Để thay đổi mã hóa mà môi trường hệ thống chỉ định, thường là UTF-8 nhưng có thể là các mã khác, hãy sử dụng setlocale (LC_CTYPE, "").

Trong Windows, VS2015 +, tuy nhiên, c32rtomb luôn chuyển đổi thành UTF-8. Vì vcruntime không hỗ trợ ngôn ngữ UTF-8 (chỉ có các miền địa phương ANSI/OEM cũ được hỗ trợ), nếu nó tuân theo chuẩn, c32rtomb/c16rtomb sẽ hoàn toàn giống với wcrtomb, và hoàn toàn không sử dụng.

Các vấn đề liên quan