Hoạt động có phải là sai <đúng hay không?


153

Thông số kỹ thuật C ++ có định nghĩa:

  1. sự tồn tại của toán tử 'nhỏ hơn' đối với các tham số boolean và nếu vậy,
  2. kết quả của 4 hoán vị tham số?

Nói cách khác, các kết quả từ các hoạt động sau được xác định bởi đặc điểm kỹ thuật?

false < false
false < true
true < false
true < true

Trong cài đặt của tôi (Centos 7, gcc 4.8.2), đoạn mã bên dưới sẽ tiết lộ những gì tôi mong đợi (với lịch sử đại diện của C là sai là 0 và đúng là 1):

false < false = false
false < true = true
true < false = false
true < true = false

Trong khi tôi khá chắc chắn rằng hầu hết các trình biên dịch (tất cả?) Sẽ cho cùng một đầu ra, điều này có được quy định bởi đặc tả C ++ không? Hoặc là một trình biên dịch khó hiểu, nhưng tuân thủ đặc tả được phép quyết định rằng true là ít hơn false?

#include <iostream>

const char * s(bool a)
{
  return (a ? "true" : "false");
}

void test(bool a, bool b)
{
  std::cout << s(a) << " < " << s(b) << " = " << s(a < b) << std::endl;
}

int main(int argc, char* argv[])
{
  test(false, false);
  test(false, true);
  test(true, false);
  test(true, true);
  return 0;
}

6
@Ul thầm Có những cách sử dụng hợp lệ. Chẳng hạn như sử dụng std::mintrên std::vector<bool>như &&.
Angew không còn tự hào về SO

19
@Ul thầm nếu bạn có thể tìm ra một câu hỏi hay chưa được hỏi sau tất cả những năm này của StackOverflow, bạn xứng đáng được một số điểm. Nó không troll.
Đánh dấu tiền chuộc

35
@Ul thầm Động lực để hỏi là chính hãng: Tôi khá mới với C ++ (đến từ C) và muốn lưu trữ một số đối tượng trong std :: set <>. Việc triển khai <toán tử của đối tượng của tôi chủ yếu dựa trên thuộc tính boolean của đối tượng, theo sau là các thuộc tính nhận dạng phụ khác. Khi lặp lại tập hợp, tôi muốn chắc chắn các đối tượng 'false' xuất hiện trước. Mặc dù nó hoạt động với tôi ở đây và bây giờ, tôi đang tìm cách đảm bảo rằng nó được đảm bảo hoạt động trên các nền tảng (bao gồm cả các nền tảng được nhúng) mà không cần phải sử dụng (a? 1: 0) hoặc tương tự, trong đối tượng của tôi < nhà điều hành.
duncan

26
Một hậu quả đáng lo ngại là điều đó p <= qcó nghĩa là p implies qkhi pqthuộc loại bool!
Theodore Norvell

4
@Technophile Có lẽ điều đáng lo ngại là <=có thể vô tình được đọc là một bên trái và rằng "chỉ khi" (nghĩa là "[về mặt vật chất] ngụ ý") đôi khi là một bộ gõ hoặc viết không chính thức tương tự như =>(ví dụ, với một trục kép =) . Một bên trái thậm chí đôi khi được đọc là "nếu", mặc dù tôi tin rằng điều này ít phổ biến hơn nhiều so với việc sử dụng một bên phải cho "chỉ khi".
Eliah Kagan

Câu trả lời:


207

TL; DR:

Các hoạt động được xác định rõ theo tiêu chuẩn dự thảo C ++.

Chi tiết

Chúng ta có thể thấy rằng bằng cách đi đến dự thảo phần tiêu chuẩn C ++ 5.9 Toán tử quan hệ có nội dung ( nhấn mạnh tôi sẽ tiếp tục ):

Các toán hạng sẽ có số học , liệt kê hoặc loại con trỏ hoặc loại std :: nullptr_t. Các toán tử <(nhỏ hơn),> (lớn hơn), <= (nhỏ hơn hoặc bằng) và> = (lớn hơn hoặc bằng) đều mang lại sai hoặc đúng. Loại kết quả là bool

và bools là các kiểu số học từ 3.9.1 Các loại cơ bản

Các loại bool , char, char16_t, char32_t, wchar_t và các kiểu số nguyên đã ký và không dấu được gọi chung là các kiểu tích phân.

Các kiểu tích phân và trôi nổi được gọi chung là các kiểu số học.

truefalselà literals boolean từ 2.14.6literals Boolean:

boolean-literal:
    false
    true

Quay trở lại phần 5.9để xem các cơ chế của các toán tử quan hệ hơn nữa, nó nói:

Các chuyển đổi số học thông thường được thực hiện trên các toán hạng thuộc loại số học hoặc liệt kê.

các chuyển đổi số học thông thường được đề cập trong phần 5có nội dung:

Mặt khác, các chương trình khuyến mãi tích hợp (4.5) sẽ được thực hiện trên cả hai toán hạng

và phần 4.5nói:

Một giá trị của loại bool có thể được chuyển đổi thành một giá trị của kiểu int, với sai trở thành 0 và đúng trở thành một.

và vì vậy các biểu thức:

false < false
false < true
true < false
true < true

sử dụng các quy tắc này trở thành:

0 < 0
0 < 1
1 < 0
1 < 1

6
Thật tuyệt, điều đó rõ ràng như bất kỳ câu trả lời nào có thể có, nhưng vẫn dễ đọc. Một nit: Tôi nghĩ rằng bạn đã in sai "loại": "Các toán hạng sẽ có số học , liệt kê hoặc loại con trỏ hoặc loại std :: nullptr_t." Thêm dấu ngoặc đơn cho rõ ràng cho loại ((số học, liệt kê hoặc con trỏ)) hoặc (loại std :: nullptr_t).

Không phải nó thay đổi câu trả lời của bạn, nhưng N3485 [over.built] / 12: Đối với mỗi cặp số học loại L và R được quảng cáo, tồn tại các hàm toán tử ứng dụng có dạng ... toán tử bool <(L, R); - Không phải các đối số được quảng bá trước các quy tắc bạn trích dẫn thậm chí áp dụng?
chris

@chris Tôi không quá quen thuộc với phần đó vì vậy tôi sẽ phải suy nghĩ về nó nhưng tôi không nghĩ câu trả lời thay đổi so với những gì tôi có thể thấy.
Shafik Yaghmour 18/03/2015

Vâng, chương trình khuyến mãi là điều đầu tiên xảy ra.
chris

63

Các giá trị Boolean tuân theo các khuyến mãi số nguyên thông thường, với falseđịnh nghĩa là 0trueđược định nghĩa là 1. Điều đó làm cho tất cả các so sánh được xác định rõ.


2
... và các toán tử quan hệ được chỉ định để thực hiện các chuyển đổi số học thông thường (bao gồm các khuyến mãi số nguyên) trên các toán hạng thuộc loại số học hoặc liệt kê.
TC

5
Tôi thích rằng câu trả lời này ngắn hơn của Shafik, nhưng tôi nghĩ rằng điểm chính falseđược xác định là 0trueđược định nghĩa như 1 trong tiêu chuẩn (thay vì chỉ bằng cách thực hành thông thường) cần bằng chứng để sao lưu.
KRyan

@KRyan gì, bạn sẽ không nhận lời của tôi cho nó? :) Trước khi có một boolloại, trước cả khi có C ++, kết quả của một phép toán boolean được định nghĩa là 0sai và 1đúng. Tôi sẽ không ngạc nhiên nếu bạn có thể tìm thấy nó trong K + R.
Đánh dấu tiền chuộc

1
@KRyan Tôi không thể quay lại quá xa như K + R, nhưng tôi đã tìm ra bản sao của Tiêu chuẩn ANSI C năm 1990. Mục 6.3.8 nói "Mỗi toán tử <(nhỏ hơn), >(lớn hơn), <=(nhỏ hơn hoặc bằng) và >=(lớn hơn hoặc bằng) sẽ mang lại 1 nếu quan hệ được chỉ định là đúng và 0 nếu nó là đúng sai. Kết quả có loại int. "
Đánh dấu tiền chuộc

1
Vấn đề lớn nhất của IIRC là trong K & R, enum bool { false = 0, true = 1}là hợp pháp nhưng không xác định operator<.
MSalters

22

Theo Tiêu chuẩn C ++ (5.9 Toán tử quan hệ)

2 Các chuyển đổi số học thông thường được thực hiện trên các toán hạng thuộc loại số học hoặc liệt kê.

1 ... Loại kết quả là bool.

và (3.9.1 Các loại cơ bản)

6 Giá trị của loại bool là đúng hoặc sai .49 [Lưu ý: Không có loại hoặc giá trị bool nào được ký, không dấu, ngắn hoặc dài. Lưu ý về tài khoản] Các giá trị của loại bool tham gia vào các chương trình khuyến mãi không thể thiếu (4.5).

và (4.5 khuyến mãi tích hợp)

6 Một giá trị của loại bool có thể được chuyển đổi thành một giá trị của kiểu int, với sai trở thành 0 và đúng trở thành một .

Vì vậy, trong tất cả các ví dụ của bạn, true được chuyển đổi thành int 1 và false được chuyển đổi thành int 0

Những biểu thức này

false < false
false < true
true < false
true < true

hoàn toàn tương đương với

0 < 0
0 < 1
1 < 0
1 < 1

8

Boolean falsetương đương với int 0, và boolean truetương đương với int 1. Vì vậy, điều này giải thích tại sao biểu thức false < true=> 0 < 1là biểu thức duy nhất trả về true.

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.