Giá trị char được đặt thành CHAR_MAX có được bảo đảm để bao quanh CHAR_MIN không?


10

Mã của tôi:

#include <stdio.h>
#include <limits.h>

int main()
{
    char c = CHAR_MAX;
    c += 1;
    printf("CHAR_MIN=%d CHAR_MAX=%d c=%d (%c)\n", CHAR_MIN, CHAR_MAX, c, c);
}

Đầu ra:

CHAR_MIN=-128 CHAR_MAX=127 c=-128 ()

Chúng ta thấy rằng khi chúng ta tăng một charbiến được đặt thành CHAR_MAX, nó sẽ bao quanh CHAR_MIN. Hành vi này có được đảm bảo không? Hoặc nó sẽ là hành vi không xác định hoặc hành vi được chỉ định thực hiện? Tiêu chuẩn C99 nói gì về điều này?

[Lưu ý: Điều gì xảy ra khi đưa giá trị lớn hơn CHAR_MAX (127) cho char hoặc C- tại sao char c = 129 sẽ chuyển đổi thành -127? không giải quyết câu hỏi này vì họ nói về việc chỉ định giá trị ngoài phạm vi không tăng giá trị cho giá trị ngoài phạm vi.]


Một sự gia tăng là một nhiệm vụ.
William Pursell

2
Nó phụ thuộc vào việc char được ký hay không dấu. Tràn số nguyên đã ký là hành vi không xác định. Vì vậy, đầu ra có thể là bất cứ điều gì.
DaBler

Câu trả lời:


15

Câu hỏi có hai mặt: Thứ nhất, là

char c = CHAR_MAX;
c += 1;

đánh giá khác với

char c = CHAR_MAX;
c = c + 1;

và câu trả lời là không , vì C11 / C18 6.5.16.2p3 :

  1. Một phép gán hỗn hợp của biểu mẫu E1 op = E2tương đương với biểu thức gán đơn giản E1 = E1 op (E2)ngoại trừ giá trị chỉ E1được đánh giá một lần và đối với lệnh gọi hàm không xác định theo trình tự, hoạt động của phép gán ghép là một đánh giá duy nhất. Nếu E1có kiểu nguyên tử, phép gán ghép là thao tác đọc-sửa-ghi với memory_order_seq_cstngữ nghĩa thứ tự bộ nhớ. 113)

Sau đó, câu hỏi là những gì xảy ra trong c = c + 1. Ở đây, toán hạng để +trải qua chuyển đổi số học thông thường, và c1do đó được thăng chức int, trừ khi một kiến trúc thực sự lập dị yêu cầu charđược thăng chức unsigned int. Việc tính toán +sau đó được ước tính và kết quả của loại int/ unsigned intđược chuyển đổi trở lại charvà được lưu trữ trong c.

3 cách xác định theo cách thực hiện, theo đó cách này có thể được đánh giá:

  • CHAR_MINlà 0 và do đó charkhông dấu.

    Hoặc charsau đó được thăng cấp lên inthoặc unsigned intnếu nó được thăng cấp thành một int, thì CHAR_MAX + 1nhất thiết sẽ phù hợp với một intquá, và sẽ không tràn, hoặc nếu unsigned intnó có thể phù hợp hoặc bao quanh bằng không. Khi giá trị kết quả, bằng số CHAR_MAX + 1hoặc 0sau khi giảm modulo, trở lại c, sau khi giảm modulo, nó sẽ trở thành 0, nghĩa làCHAR_MIN

  • Mặt khác charđược ký, nếu CHAR_MAX nhỏ hơn INT_MAX, kết quả CHAR_MAX + 1sẽ phù hợp với intC11 / C18 6.3.1.3p3 tiêu chuẩn áp dụng cho chuyển đổi xảy ra khi gán :

    1. Mặt khác, loại mới được ký và giá trị không thể được biểu diễn trong đó; hoặc kết quả là xác định thực hiện hoặc tín hiệu xác định thực hiện được đưa ra.
  • Hoặc, iff sizeof (int) == 1 char được ký, sau đó charđược thăng cấp thành intCHAR_MAX == INT_MAX=> CHAR_MAX + 1sẽ gây ra tràn số nguyên và hành vi sẽ không được xác định .

Tức là kết quả có thể là:

  • Nếu charlà một kiểu số nguyên không dấu, kết quả luôn luôn là 0, tức là CHAR_MIN.

  • Mặt khác charlà một kiểu số nguyên đã ký và hành vi được xác định thực hiện / không xác định:

    • CHAR_MIN hoặc một số giá trị được xác định thực hiện khác,
    • một tín hiệu xác định thực hiện được đưa ra, có thể chấm dứt chương trình,
    • hoặc hành vi không được xác định trên một số nền tảng trong đó sizeof (char) == sizeof (int).

Tất cả các hoạt động tăng c = c + 1, c += 1, c++++ccó tác dụng phụ như nhau trên cùng một nền tảng. Giá trị được đánh giá của biểu thức c++sẽ là giá trị ctrước khi tăng; đối với ba phần còn lại, nó sẽ là giá trị csau khi tăng.


1
sizeof(int) == 1sẽ yêu cầu CHAR_BITS >= 16, phải không?
sepp2k

3
@ sepp2k <pedantic>IDK về CHAR_BITSnhưng CHAR_BITsẽ >= 16</pedantic>.
Antti Haapala

2
Một lý do nữa tại sao charphải luôn luôn được đánh dấu theo mặc định.
chqrlie

1
Tài khoản @chqrlie char ..
Antti Haapala

1
Đôi khi cũng rõ ràng để thêm một câu trả lời trực tiếp: "Giá trị char được đặt thành CHAR_MAX có được bảo đảm để bao quanh CHAR_MIN không?" -> Số
chux - Phục hồi Monica
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.