toán tử bool ++ và -


104

Hôm nay trong khi viết một số mã Visual C ++, tôi đã bắt gặp một thứ khiến tôi ngạc nhiên. Có vẻ như C ++ hỗ trợ ++ (tăng) cho bool, nhưng không - (giảm). Nó chỉ là một quyết định ngẫu nhiên, hay có một số lý do đằng sau điều này?

Điều này biên dịch:

static HMODULE hMod = NULL;
static bool once = false;
if (!once++)
    hMod = LoadLibrary("xxx");

Điều này không:

static HMODULE hMod = NULL;
static bool once = true;
if (once--)
    hMod = LoadLibrary("xxx");

2
hm, tương tự cho xcode và gcc biên dịch
Vladimir

Đúng, ++onceonce++làm việc với gcc, nhưng không làm việc với các giảm.
Justin Ardini

Có thể gắn thẻ lại "lịch sử" thay vì "từ khóa toán tử", vì vậy điều này được nhóm với tất cả các giải thích thú vị khác tại sao những điều điên rồ khác nhau là hợp lý nếu bạn xem xét lịch sử? :)
Jon Hanna

Lưu ý là trong C ++ 17 nhà điều hành trước increment cho boolbị phản đối, souce .
cogle

điều này có thể được thay thế bằng std::exchange(once,false)(lưu ý: không phải nguyên tử), nếu bạn muốn một cái gì đó không bị phản đối.
golvok

Câu trả lời:


90

Nó xuất phát từ lịch sử sử dụng các giá trị số nguyên làm boolean.

Nếu xlà một int, nhưng tôi đang sử dụng nó như một boolean if(x)...thì tăng dần sẽ có nghĩa là bất kể giá trị chân lý của nó trước hoạt động, nó sẽ có giá trị chân lý truesau nó (chặn tràn).

Tuy nhiên, không thể dự đoán kết quả của --kiến thức đã cho chỉ về giá trị chân lý của x, vì nó có thể dẫn đến false(nếu giá trị tích phân là 1) hoặc true(nếu giá trị tích phân là bất kỳ thứ gì khác - đặc biệt là điều này bao gồm 0 [ false] và 2 hoặc thêm [ true]).

Vì vậy, như một bàn tay ngắn ++đã hoạt động, và --không.

++ được cho phép trên bools để tương thích với điều này, nhưng việc sử dụng nó không được chấp nhận trong tiêu chuẩn.


Điều này giả định rằng tôi chỉ sử dụng xnhư một boolean, có nghĩa là tràn không thể xảy ra cho đến khi tôi thực hiện ++đủ thường xuyên để gây ra tràn. Ngay cả với char là loại được sử dụng và CHAR_BITSmột cái gì đó thấp như 5, đó là 32 lần trước khi điều này không hoạt động nữa (điều đó vẫn đủ lập luận cho nó là một thực hành xấu, tôi không bảo vệ phương pháp này, chỉ giải thích tại sao nó hoạt động) đối với 32-bit, inttất nhiên, chúng tôi sẽ phải sử dụng ++2 ^ 32 lần trước khi điều này xảy ra. Với --mặc dù nó sẽ chỉ dẫn đến falsenếu tôi bắt đầu với giá trị 1 cho truehoặc bắt đầu bằng 0 và được sử dụng ++chính xác một lần trước đó.

Điều này sẽ khác nếu chúng ta bắt đầu với một giá trị nhỏ hơn 0. Thật vậy, trong trường hợp như vậy, chúng ta có thể muốn ++dẫn đến falsegiá trị cuối cùng chẳng hạn như trong:

int x = -5;
while(++x)
  doSomething(x);

Tuy nhiên, ví dụ này được coi xintở mọi nơi ngoại trừ điều kiện, vì vậy nó tương đương với:

int x = -5;
while(++x != 0)
  doSomething(x);

Khác với việc chỉ sử dụng xlàm boolean.


1
Cảm ơn bạn. Thật tuyệt khi biết tôi vẫn có thể cung cấp câu trả lời những người như về vấn đề này, được đưa ra bao lâu nó được kể từ khi tôi đã thực sự viết một dòng của C ++ :)
Jon Hanna

8
Nhưng nếu x là -1 (TRUE trong một số nền tảng như VB), ++ x sẽ là FALSE.
James Curran

4
@James, trong C và C ++, đó sẽ là trường hợp tôi nghĩ đến khi tôi nói ("cấm tràn"). Trên thực tế trong VB, bất kỳ khác 0 nào đều có giá trị chân lý TRUE (như trong C), nhưng chúng có -1 thay vì 1 do kết quả của các phép toán boolean thực sự vì vậy NOT (TRUE) là FALSE, NOT (FALSE) là TRUE, x OR TRUE là TRUE, x OR FALSE là x, x AND FALSE là FALSE và x AND TRUE là x, v.v. sử dụng các toán tử tương tự cho các phép toán boolean và bit-khôn (vì VB giả sử bổ sung hai phần nên -1 là tất cả 1 bit). Tuy nhiên, điều này có thể gây ra một số lỗi lạ trong VB nếu người viết mã không nắm bắt được kết quả 2 (đúng) VÀ 4 (đúng) là 0 (sai).
Jon Hanna

2
@JonHanna: ANSI C89 là tiêu chuẩn C đầu tiên. Ủy ban ANSI C đã phát minh ra <limits.h>tiêu đề và CHAR_BITmacro. Trước đó, tôi cho rằng về mặt lý thuyết có thể đã có những triển khai ở nơi charhẹp hơn 8 bit, nhưng theo như tôi biết thì không có. Đặc biệt, K & R1 (xuất bản năm 1978) liệt kê 4 cách triển khai mẫu, tất cả đều có 8-bit hoặc 9-bit char.
Keith Thompson

1
@JonHanna: Một phù hợp C thực hiện phảiCHAR_BIT >= 8. Tiêu chuẩn không đưa ra mức phụ cấp cho các mục tiêu khó. (Tất nhiên, bạn có thể có một triển khai không phù hợp.)
Keith Thompson

29

ANSI ISO IEC 14882 2003 (c ++ 03):

5.2.6-2

Toán hạng của postfix - được giảm dần tương tự với toán tử postfix ++, ngoại trừ toán hạng sẽ không có kiểu bool. [Lưu ý: Để biết tăng và giảm tiền tố, xem 5.3.2. ]

Và không ngạc nhiên ...

5.3.2-2

Toán hạng của tiền tố - được sửa đổi bằng cách trừ đi 1. Toán hạng sẽ không thuộc loại bool. Các yêu cầu đối với toán hạng của tiền tố - và các thuộc tính của kết quả của nó khác với các thuộc tính của tiền tố ++. [Lưu ý: Đối với tăng và giảm hậu tố, xem 5.2.6. ]

Ngoài ra, 5.6.2-1 và 5.3.2-1 cũng đề cập rằng ++ đối với bools sẽ đúng và Phụ lục D-1 nói rằng ++ trên bools không được chấp nhận.


3
@BlueRaja: Hãy xem câu trả lời của Jon Hanna.
Justin Ardini

9

Vì lý do lịch sử, điều này đã được hỗ trợ. Nhưng lưu ý rằng ... Việc sử dụng toán hạng kiểu bool với toán tử ++ không được chấp nhận, hãy xem Phần 5.3.2 trong Tiêu chuẩn C ++ (n3092)

5.3.2 Tăng và giảm [expr.pre.incr]

  • Toán hạng của tiền tố ++ được sửa đổi bằng cách thêm 1 hoặc đặt thành true nếu nó là bool (việc sử dụng này không được chấp nhận). Toán hạng phải là một giá trị có thể sửa đổi. Kiểu của toán hạng phải là kiểu số học hoặc một con trỏ tới kiểu đối tượng hoàn toàn được xác định. Kết quả là toán hạng được cập nhật; nó là một giá trị và nó là một trường bit nếu toán hạng là một trường bit. Nếu x không thuộc kiểu bool, biểu thức ++ x tương đương với x + = 1 [Lưu ý: xem thảo luận về phép cộng (5.7) và toán tử gán (5.17) để biết thông tin về chuyển đổi. —Gửi ghi chú]
  • Toán hạng của tiền tố - được sửa đổi bằng cách trừ đi 1. Toán hạng sẽ không thuộc loại bool. Các yêu cầu đối với toán hạng của tiền tố - và các thuộc tính của kết quả của nó khác với các thuộc tính của tiền tố ++.

3
  • Với các tiêu chuẩn cũ (C ++ 98) nó không phải là một lỗi.
  • Với các tiêu chuẩn mới, boolean không còn được dùng nữa. (C ++ 11)
  • Bạn có thể sử dụng tăng dần trên boolean cho đến C ++ 17.
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.