2013-08-14 42 views
10

Dường như có khả năng đồng bằng char có thể được ký hoặc không được ký theo mặc định. Stroustrup viết:Làm cách nào để kiểm tra xem ký tự thuần túy có được ký hoặc chưa ký?

Nó được thực hiện xác định xem một đồng bằng char được coi là ký hoặc chưa ký. Điều này mở ra khả năng cho một số bất ngờ khó chịu và phụ thuộc triển khai.

Làm cách nào để kiểm tra xem ký tự của tôi đã được ký hoặc chưa ký? Tôi có thể muốn chuyển đổi chúng thành int sau đó và tôi không muốn chúng bị âm. Tôi có nên sử dụng unsigned char một cách rõ ràng không?

+0

@MitchWheat: Có. Ví dụ tôi đã gặp phải: Cray T90, Cray SV1, Cray T3E, SGI MIPS IRIX, IBM PowerPC AIX. Và bất kỳ hệ thống nào sử dụng EBCDIC khá nhiều đều phải làm đơn giản 'char' unsigned. –

+0

@KeithThompson: Bạn nên thêm danh sách của mình làm câu trả lời cho [câu hỏi này] (http://stackoverflow.com/questions/3728045/any-compiler-which-takes-char-as-unsigned) – jxh

+0

Bạn đọc tài liệu của trình biên dịch . –

Trả lời

13

Một số lựa chọn thay thế:

const bool char_is_signed = (char)-1 < 0; 

#include <climits> 
const bool char_is_signed = CHAR_MIN < 0; 

Và vâng, một số hệ thống nào làm cho đồng bằng char một kiểu unsigned. Ví dụ tôi đã gặp phải: Cray T90, Cray SV1, Cray T3E, SGI MIPS IRIX, IBM PowerPC AIX. Và bất kỳ hệ thống nào sử dụng EBCDIC đều phải làm cho đồng bằng char không được ký sao cho tất cả các ký tự cơ bản đều có giá trị không âm. (Và một số trình biên dịch có một tùy chọn để kiểm soát signedness của char, chẳng hạn như gcc của -fsigned-char-funsigned-char.)

Nhưng std::numeric_limits<char>::is_signed, theo đề nghị của Benjamin Lindley's answer, có lẽ thể hiện mục đích rõ ràng hơn.

(Mặt khác, các phương pháp tôi đề nghị cũng có thể được áp dụng cho C.)

-1

Bạn có thể sử dụng lệnh tiền xử lý:

#define is_type_signed(my_type) (((my_type)-1) < 0) 
+3

Tại sao làm cho nó một vĩ mô hơn là, nói, một 'const bool'? –

+0

@KeithThompson Đây là cấu trúc "phổ quát" hơn, không chỉ cho các loại char. –

+2

Các 'số_limits <> :: is_signed' đã bao gồm bất kỳ ý nghĩa của" phổ quát "bạn đang cố gắng để truyền đạt. – jxh

0

Sử dụng unsigned char "luôn luôn" có thể cung cấp cho bạn một số bất ngờ thú vị , như phần lớn các chức năng kiểu C như printf, fopen, sẽ sử dụng char, không phải unsigned char.

chỉnh sửa: Ví dụ về "vui vẻ" với các chức năng C-style:

const unsigned char *cmd = "grep -r blah *.txt"; 
FILE *pf = popen(cmd, "r"); 

sẽ cung cấp cho các lỗi (trong thực tế, tôi nhận được một cho dòng *cmd =, và một lỗi cho các dòng popen). Sử dụng const char *cmd = ... sẽ hoạt động tốt. Tôi nhặt popen bởi vì nó là một chức năng đó không phải là tầm thường để thay thế với một số tiêu chuẩn C++ chức năng - rõ ràng, printf hoặc fopen có thể khá dễ dàng được thay thế bằng một số chức năng iostream hoặc fstream loại, mà thường có lựa chọn thay thế mà phải mất unsigned char cũng như char.

Tuy nhiên, nếu bạn đang sử dụng > hoặc < trên ký tự vượt quá 127, sau đó bạn sẽ cần phải sử dụng unsigned char (hoặc một số giải pháp khác, chẳng hạn như đúc để int và mặt nạ 8 bit thấp hơn).Nó có lẽ là tốt hơn để cố gắng tránh so sánh trực tiếp (đặc biệt là khi nói đến các ký tự không phải ASCII - chúng vẫn lộn xộn, bởi vì thường có một số biến thể tùy thuộc vào ngôn ngữ, mã hóa ký tự, vv). So sánh bình đẳng nên làm việc tuy nhiên.

+0

@chux: Xem chỉnh sửa ... –

+0

@chux: Chưa hoàn tất chỉnh sửa ... (lưu ý: Tự chỉnh sửa trước, sau đó nhận xét để nói "xem chỉnh sửa") –

0

Có, nếu bạn muốn sử dụng loại char và bạn luôn muốn nó không được ký, hãy sử dụng unsigned char. Lưu ý rằng không giống như các loại số nguyên cơ bản khác, unsigned char là một loại khác từ char - ngay cả trên các hệ thống trong đó char chưa được ký. Ngoài ra, chuyển đổi từ char thành intought to be lossless vì vậy nếu kết quả của bạn không chính xác, giá trị của bạn char cũng có thể không chính xác.

Cách sạch nhất để kiểm tra xem char chưa được ký phụ thuộc vào việc bạn có cần nó làm kiểm thử tiền xử lý và phiên bản C++ bạn đang nhắm mục tiêu hay không.

Để có điều kiện biên dịch mã sử dụng một thử nghiệm tiền xử lý, giá trị của CHAR_MIN nên làm việc:

#include <climits> 

#if (CHAR_MIN==0) 
// code that relies on char being unsigned 
#endif 

Trong C++ 17 tuổi, tôi sẽ sử dụng std::is_signed_vstd::is_unsigned_v:

#include <type_traits> 

static_assert(std::is_unsigned_v<char>); 
// code that relies on char being unsigned 

Nếu bạn là viết chống lại C++ 11 hoặc C++ 14 bạn cần thêm một chút chi tiết std::is_signedstd::is_unsigned:

#include <type_traits> 

static_assert(std::is_unsigned<char>::value, "char is signed"); 
// code that relies on char being unsigned 

Đối với tất cả các bản sửa đổi của C++, giải pháp @ benjamin-lindley là giải pháp thay thế tốt.

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