Là char được ký hoặc không dấu theo mặc định?


158

Trong cuốn sách "Tham chiếu đầy đủ về C", nó được đề cập chartheo mặc định không dấu.

Nhưng tôi đang cố gắng xác minh điều này với GCC cũng như Visual Studio. Người ta dùng nó như là theo mặc định.

Cái nào đúng?


5
Cuốn sách tham khảo C mà tôi tin tưởng là "C: A Reference Guide" của Harbison & Steele ( careferencemanual.com ). Tất nhiên tiêu chuẩn là từ cuối cùng, nhưng nó không dễ đọc lắm và chỉ cung cấp thông tin nhỏ nhất về việc sử dụng trước tiêu chuẩn và phổ biến (ví dụ: POSIX) nằm ngoài tiêu chuẩn. Harbison & Steele khá dễ đọc, chi tiết và có lẽ đúng hơn hầu hết các tài liệu tham khảo. Tuy nhiên nó cũng không phải là một hướng dẫn, vì vậy nếu bạn đang ở giai đoạn đầu học thì có lẽ không phải là một điều tuyệt vời để nhảy vào.
Michael Burr

15
Tôi nghĩ cuốn sách bạn đang đọc là C: The Complete Reference , của Herbert Schildt. Từ đánh giá của cuốn sách này ( accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm ): Tôi sẽ không đề xuất cuốn sách này (quá nhiều bạn cho quá nhiều ý kiến ​​của tôi) nhưng Tôi không nghĩ rằng nó xứng đáng với cùng một quan điểm đã được ném một cách hợp pháp vào một số công việc khác của mình. Như Michael nói, một tài liệu tham khảo tốt hơn nhiều là Harbison & Steele .
Alok Singhal

Hai xu của tôi ở đây: Bởi vì charcó thể không dấu, vì quy tắc sử dụng intđể đọc giá trị sử dụng getchar(), có thể trả về EOF. EOFthường được định nghĩa là -1hoặc giá trị âm khác, lưu trữ trong một unsignedkhông phải là những gì bạn muốn. Đây là tuyên bố: extern int getchar();BTW, khuyến nghị này cũng xuất phát từ cuốn sách "C: A Reference Guide".
Maxim Chetrusca

6
Tài liệu tham khảo C mà tôi tin tưởng là ISO / IEC 9899: 2011 :-)
Jeff

3
@MaxChetrusca lời khuyên tốt nhưng lý do xấu: ngay cả trong chartrường hợp đã ký , bạn phải sử dụng intđể lưu trữ giá trị trả về.
Antti Haapala

Câu trả lời:


204

Cuốn sách sai. Tiêu chuẩn không chỉ định nếu đồng bằng charđược ký hoặc không dấu.

Trong thực tế, tiêu chuẩn định nghĩa ba loại khác nhau: char, signed char, và unsigned char. Nếu bạn #include <limits.h>và sau đó nhìn vào CHAR_MIN, bạn có thể tìm hiểu xem đơn giản charsignedhoặc unsigned(nếu CHAR_MINnhỏ hơn 0 hoặc bằng 0), nhưng ngay cả khi đó, ba loại là khác biệt theo tiêu chuẩn.

Hãy lưu ý rằng đó charlà đặc biệt theo cách này. Nếu bạn khai báo một biến vì intnó tương đương 100% với khai báo nó là signed int. Điều này luôn đúng với tất cả các trình biên dịch và kiến ​​trúc.


1
@Alok: điều tương tự không đúng với một số kiểu dữ liệu khác, ví dụ intcó nghĩa là signed intluôn luôn, phải không? Ngoài ra char, những kiểu dữ liệu khác có cùng một sự nhầm lẫn trong C?
Lazer

8
@eSKay: có, charlà loại duy nhất có thể được ký hoặc không dấu. inttương đương signed intvới ví dụ.
Alok Singhal

28
Có một lý do lịch sử, cuồng loạn cho điều này - ngay từ đầu đời C, "tiêu chuẩn" đã bị lật ít nhất hai lần, và một số trình biên dịch ban đầu phổ biến đã kết thúc theo cách này và cách khác.
Hot Licks

9
@AlokSinghal: Nó cũng được xác định bằng cách xác định xem một trường loại bit intđược ký hay không dấu.
Keith Thompson

@KeithThndry cảm ơn đã sửa. Tôi có xu hướng quên một số chi tiết về các loại trường bit vì tôi không sử dụng chúng nhiều.
Alok Singhal

68

Như Alok chỉ ra , các tiêu chuẩn để lại cho đến khi thực hiện.

Đối với gcc, mặc định được ký, nhưng bạn có thể sửa đổi điều đó với -funsigned-char. lưu ý: đối với gcc trong Android NDK, mặc định là không dấu . Bạn cũng có thể yêu cầu rõ ràng cho các ký tự được ký với -fsigned-char.

Trên MSVC, mặc định được ký nhưng bạn có thể sửa đổi điều đó với /J.


2
Điều thú vị là mô tả của Schildt không phù hợp với hành vi của MSVC vì sách của ông thường hướng đến người dùng MSVC. Tôi tự hỏi nếu MS thay đổi mặc định tại một số điểm?
Michael Burr

1
Tôi nghĩ rằng nó không phụ thuộc vào trình biên dịch, nhưng trên nền tảng. Tôi nghĩ char được để lại như một loại "kiểu dữ liệu ký tự" thứ ba để phù hợp với những gì các hệ thống tại thời điểm đó được sử dụng làm ký tự có thể in được.
Spidey

10
Các tài liệu của GCC nói rằng nó phụ thuộc vào máy: " Mỗi loại máy đều có mặc định cho char là gì. Nó giống như char không dấu theo mặc định hoặc như char được ký theo mặc định. "
Ded repeatator

1
Bạn có thể vui lòng cung cấp một nguồn cho ghi chú của bạn rằng trên Android mặc định là char không dấu?
phlipsy

1
@Spidey tiêu chuẩn C không phân biệt thực sự giữa trình biên dịch, nền tảng và kiến ​​trúc CPU. Nó chỉ gộp tất cả chúng lại với nhau dưới "thực hiện".
cắm vào

35

Bản dự thảo C99 N1256 6.2.5 / 15 "Các loại" có ý nghĩa này để nói về tính chất đã ký của loại char:

Việc thực hiện sẽ xác định char có cùng phạm vi, biểu diễn và hành vi như char đã ký hoặc char không dấu.

và trong một chú thích:

CHAR_MIN, được xác định trong <limits.h>, sẽ có một trong các giá trị 0hoặc SCHAR_MIN, và điều này có thể được sử dụng để phân biệt hai tùy chọn. Bất kể sự lựa chọn nào, charlà một loại riêng biệt với hai loại kia và không tương thích với một trong hai.


7

Theo cuốn sách Ngôn ngữ lập trình C của Dennis Ritchie, đây là cuốn sách tiêu chuẩn thực tế cho ANSI C, các ký tự đơn giản được ký hoặc không dấu đều phụ thuộc vào máy, nhưng các ký tự có thể in luôn luôn dương.


9
Không nhất thiết là các ký tự có thể in luôn luôn dương. Tiêu chuẩn C đảm bảo rằng tất cả các thành viên của bộ ký tự thực hiện cơ bản có các giá trị không âm.
Keith Thompson

7

Theo tiêu chuẩn C, chữ ký của char đơn giản là "xác định thực hiện".

Nhìn chung, những người triển khai đã chọn cách nào hiệu quả hơn để thực hiện trên kiến ​​trúc của họ. Trên hệ thống x86 char thường được ký. Trên các hệ thống cánh tay, nó thường không được ký (Apple iOS là một ngoại lệ).



2
@plugwash Câu trả lời của bạn có thể bị hạ thấp vì Tim Post bị mất chìa khóa . Nghiêm túc mà nói, bạn không nên lo lắng về một downvote duy nhất miễn là bạn chắc chắn câu trả lời của mình là đúng (trong trường hợp này). Nó đã xảy ra với tôi nhiều lần để bài viết của tôi bị hạ cấp mà không có lý do chính đáng. Đừng lo lắng về điều đó, đôi khi mọi người chỉ làm những điều kỳ lạ.
Vịt Donald

1
Tại sao ký char hiệu quả hơn trên x86? Nguồn nào?
martinkunev

2

Theo "Ngôn ngữ lập trình C ++" của Bjarne Stroustrup, charlà "triển khai được xác định". Nó có thể signed charhoặc unsigned chartùy thuộc vào việc thực hiện. Bạn có thể kiểm tra xem có charđược ký hay không bằng cách sử dụng std::numeric_limits<char>::is_signed.


9
Đây là một câu hỏi C. C ++ là một ngôn ngữ khác và các tham chiếu C ++ không liên quan đến C.
MM

1

Bây giờ, chúng tôi đã biết các lá tiêu chuẩn cho đến khi thực hiện.

Nhưng làm thế nào để kiểm tra một loại là signedhay unsigned, chẳng hạn như char?

Tôi đã viết một macro để làm điều này:

#define IS_UNSIGNED(t) ((t)~1 > 0)

và thử nghiệm nó với gcc, clangcl. Nhưng tôi không chắc nó luôn an toàn cho các trường hợp khác.


Điều gì sai với CHAR_MIN thông thường <0 (hoặc WCHAR_MIN <0 cho wchar_t)?
Tiö Tiib
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.