2010-03-26 30 views
10

Tôi đọc rằng C không xác định nếu một ký tự được ký hoặc chưa ký, và trong trang GCC, nó có thể được ký trên x86 và không được ký trong PowerPPC và ARM.Câu hỏi của Char C về mã hóa đã ký/chưa ký

Okey, tôi đang viết một chương trình với GLIB xác định char là gchar (không nhiều hơn nó, chỉ là một cách để tiêu chuẩn hóa).

Câu hỏi của tôi là, UTF-8 là gì? Nó sử dụng nhiều hơn một khối bộ nhớ?

Nói rằng tôi có một biến

unsigned char * string = "string của tôi với UTF8 enconding ~> CA";

Xem, nếu tôi khai báo biến tôi như

unsigned

tôi sẽ chỉ có 127 giá trị (do chương trình của tôi sẽ để lưu trữ nhiều hơn các khối mem) hoặc UTF-8 thay đổi thành âm?

Xin lỗi nếu tôi không thể giải thích chính xác, nhưng tôi nghĩ rằng tôi hơi phức tạp một chút.

LƯU Ý: Cảm ơn tất cả trả lời

Tôi không hiểu làm thế nào nó được giải thích thông thường.

Tôi nghĩ rằng như ascii, nếu tôi có một chữ ký và unsigned char trên chương trình của tôi, các chuỗi có giá trị khác nhau, và nó dẫn đến nhầm lẫn, tưởng tượng nó trong utf8 như vậy.

+0

Nếu bạn đang sử dụng một máy tính hiện đại, unsigned char sẽ hỗ trợ các giá trị 0..255. Nhưng UTF-8 là một mã hóa nhiều byte - nó sử dụng 1,.4 byte cho mỗi ký tự Unicode. –

+0

Tôi đang nói về @Michael Burr nói. – drigoSkalWalker

Trả lời

1

Không thực sự, unsigned/signed không chỉ định số lượng giá trị mà một biến có thể giữ. Nó chỉ định cách chúng được diễn giải.

Vì vậy, unsigned char có cùng số lượng giá trị dưới dạng signed char, ngoại trừ số có giá trị âm và số kia thì không. Nó vẫn còn 8 bit (nếu chúng ta giả định rằng char giữ 8 bit, tôi không chắc chắn nó có ở mọi nơi).

+1

Chuẩn C đảm bảo rằng ký tự chứa ít nhất 8 bit; có vài máy nhân vật 9 bit hoặc 10 bit còn lại. –

2

đã ký/không ký chỉ ảnh hưởng đến các phép tính số học. nếu char chưa được ký thì giá trị cao hơn sẽ dương. trong trường hợp đã ký, chúng sẽ âm. Nhưng phạm vi vẫn giống nhau.

1

Không có sự khác biệt khi sử dụng char * làm chuỗi. Thời gian duy nhất được ký/unsigned sẽ tạo sự khác biệt là nếu bạn sẽ giải thích nó như là một số, như cho số học hoặc nếu bạn đã in nó như là một số nguyên.

+2

Nó cũng có thể tạo sự khác biệt nếu bạn so sánh các ký tự. Ví dụ, trong trường hợp UTF8, các ký tự 'cờ' nói chung sẽ là số âm nếu 'char' được ký. Nếu mã của bạn không được chuẩn bị cho điều đó, mọi thứ sẽ bị phá vỡ. –

+0

Bạn có thể giải thích thêm một chút không? – drigoSkalWalker

+0

@Michael Burr Tôi không biết điều đó, bạn có tham khảo không? –

0

UTF-8 ký tự không thể giả định để lưu trữ trong một byte. Các ký tự UTF-8 có thể rộng 1-4 byte. Vì vậy, một char, wchar_t, signed hoặc unsigned sẽ không đủ để giả sử một đơn vị luôn có thể lưu trữ một ký tự UTF-8.

Hầu hết các nền tảng (chẳng hạn như PHP, .NET, v.v.) đều tạo chuỗi bình thường (chẳng hạn như char[] trong C) và bạn sử dụng thư viện để chuyển đổi giữa mã hóa và phân tích cú pháp các ký tự.

+0

vâng, Rõ ràng là tôi cần một ARRAY của ký tự, nhưng câu hỏi của tôi là về ký và unsigned, nghĩ rằng nếu tôi có một ARRAY singed hoặc unsigned của ký tự có thể làm cho chương trình của tôi chạy sai? – drigoSkalWalker

+0

Các câu trả lời khác là chính xác khi nói rằng ký/unsigned không thay đổi kích thước của dữ liệu được lưu trữ. Mối quan tâm của tôi chỉ là UTF-8 có thể nhiều hơn một byte cho các ký tự UTF-8 từ Kanji, tiếng Ả Rập, v.v. – spoulson

6

Tôi đã có một vài yêu cầu giải thích nhận xét mà tôi đã đưa ra.

Thực tế là loại char có thể mặc định là loại đã ký hoặc chưa ký có thể có ý nghĩa khi bạn so sánh các ký tự và mong đợi một thứ tự nhất định. Cụ thể, UTF8 sử ​​dụng bit cao (giả sử rằng char là loại 8 bit, đúng trong phần lớn các nền tảng) để chỉ ra rằng một điểm mã ký tự yêu cầu nhiều hơn một byte được biểu diễn.

Một ví dụ nhanh chóng và dơ bẩn của vấn đề:

#include <stdio.h> 
int main(void) 
{ 
    signed char flag = 0xf0; 
    unsigned char uflag = 0xf0; 

    if (flag < (signed char) 'z') { 
     printf("flag is smaller than 'z'\n"); 
    } 
    else { 
     printf("flag is larger than 'z'\n"); 
    }  


    if (uflag < (unsigned char) 'z') { 
     printf("uflag is smaller than 'z'\n"); 
    } 
    else { 
     printf("uflag is larger than 'z'\n"); 
    } 
    return 0; 
} 

Trên hầu hết các dự án mà tôi làm việc, không trang trí char loại thường tránh ủng hộ chúng tôi bằng một typedef đó một cách rõ ràng xác định một unsigned char. Một cái gì đó giống như uint8_t từ stdint.h hoặc

typedef unsigned char u8; 

Nói chung đối phó với một loại unsigned char dường như làm việc tốt và có vài vấn đề - một trong những khu vực mà tôi đã nhìn thấy vấn đề thường xuyên là khi sử dụng một cái gì đó của loại hình đó để kiểm soát một vòng lặp:

while (uchar_var-- >= 0) { 
    // infinite loop... 
} 
3

Hai điều:

  1. Cho dù một kiểu char được ký kết hoặc unsigned sẽ không ảnh hưởng đến khả năng dịch các chuỗi được mã hóa UTF8 của bạn đến và từ bất kỳ loại chuỗi hiển thị nào bạn đang sử dụng (WCHAR hoặc whatnot). Đừng lo lắng về nó, nói cách khác: các byte UTF8 chỉ là byte, và bất cứ điều gì bạn đang sử dụng như một bộ mã hóa/giải mã sẽ làm điều đúng.

  2. Một số nhầm lẫn của bạn có thể là bạn đang cố gắng để làm điều này:

    unsigned char *string = "This is a UTF8 string"; 
    

    Đừng làm điều này-- bạn đang trộn khái niệm khác nhau. Một chuỗi được mã hóa UTF-8 chỉ là một chuỗi các byte. C string literals (như trên) đã không thực sự được thiết kế để đại diện cho điều này; chúng được thiết kế để thể hiện các chuỗi "được mã hóa ASCII". Mặc dù đối với một số trường hợp (như của tôi ở đây) họ kết thúc được điều tương tự, trong ví dụ của bạn trong câu hỏi, họ có thể không. Và chắc chắn trong những trường hợp khác, chúng sẽ không như vậy. Tải chuỗi Unicode của bạn từ một tài nguyên bên ngoài. Nói chung tôi muốn cảnh giác với việc nhúng các ký tự không phải ASCII vào một tệp nguồn .c; ngay cả khi trình biên dịch biết phải làm gì với chúng, các phần mềm khác trong toolchain của bạn có thể không.

5

Sử dụng dấu chưa ký có ưu và khuyết điểm của nó. Lợi ích lớn nhất là bạn không nhận được tiện ích mở rộng dấu hiệu hoặc các tính năng vui nhộn khác như tràn đã ký sẽ tạo ra kết quả không mong muốn từ các tính toán. Unsigned char cũng tương thích với <cctype> macro/chức năng như isalpha (ch) (tất cả các giá trị này yêu cầu trong phạm vi char chưa ký). Mặt khác, tất cả các hàm I/O yêu cầu char *, yêu cầu bạn cast bất cứ khi nào bạn làm I/O.

Đối với UTF-8, lưu trữ nó trong mảng đã ký hoặc chưa ký là tốt nhưng bạn phải cẩn thận với các chuỗi ký tự này vì có rất ít đảm bảo về chúng là UTF-8 hợp lệ. C++ 0x bổ sung thêm các chuỗi ký tự UTF-8 để tránh các vấn đề có thể xảy ra và tôi mong đợi chuẩn C tiếp theo sẽ áp dụng chúng.

Nói chung, bạn nên ổn, miễn là bạn đảm bảo rằng các tệp mã nguồn của bạn luôn được mã hóa UTF-8.

0

Như cho câu hỏi you'r:

nghĩ rằng nếu tôi có một ARRAY đã ký kết hoặc unsigned chars có thể nó làm cho chương trình của tôi chạy sai? - drigoSkalWalker

Có. Tôi đã làm. Heres một đoạn trích chạy đơn giản từ ứng dụng của tôi mà hoàn toàn đi ra sai nếu sử dụng ký tự bình thường đã ký. Thử chạy sau khi thay đổi tất cả các ký tự thành các tham số chưa được ký. Như thế này:

int is_valid (unsigned char c);

sau đó nó sẽ hoạt động bình thường.

#include <stdio.h> 

int is_valid(char c); 

int main() { 

    char ch = 0xFE; 
    int ans = is_valid(ch); 
    printf("%d", ans); 

} 

int is_valid(char c) { 
    if((c == 0xFF) || (c == 0xFE)) { 
    printf("NOT valid\n"); 
     return 0; 
    } 
    else { 
     printf("valid\n") 
     return 1; 
    } 
} 

Điều gì sẽ xác thực nếu char là byte hợp lệ trong utf-8. 0xFF và 0xFE KHÔNG phải là byte hợp lệ trong utf-8. hãy tưởng tượng vấn đề nếu hàm xác nhận nó là một byte hợp lệ?

những gì xảy ra là thế này:

0xFE 
= 
11111110 
= 
254 

Nếu bạn lưu này trong một char bình thường (có chữ ký) bit tận cùng bên trái, bit quan trọng nhất, làm cho nó tiêu cực. Nhưng số âm là gì?

Nó thực hiện điều này bằng cách lật các bit và thêm một bit.

11111110 
00000001 
00000001 + 00000001 = 
00000010 = 2 

và nhớ nó đã làm cho nó tiêu cực, vì vậy nó trở nên -2

như vậy (-2 == 0xFE) trong hàm ofcourse isnt đúng. tương tự với (-2 == 0xFF).

Vì vậy, chức năng kiểm tra các byte không hợp lệ sẽ kết thúc xác thực các byte không có giá trị như thể chúng là ok: -o.

Hai lý do khác tôi có thể nghĩ ra để dính vào unsigned khi giao dịch với utf-8 là:

  1. Nếu bạn có thể cần một số bitshifting sang bên phải, có thể có rắc rối bởi vì sau đó bạn có thể kết thúc thêm 1 từ bên trái nếu sử dụng ký tự đã ký.

  2. utf-8 và unicode chỉ sử dụng số dương nên ... tại sao bạn cũng vậy? giữ nó đơn giản :)