Tại sao, size sizeof (a? True: false) đưa ra một đầu ra gồm bốn byte?


133

Tôi có một đoạn mã nhỏ về sizeoftoán tử với toán tử ternary:

#include <stdio.h>
#include <stdbool.h>

int main()
{
    bool a = true;
    printf("%zu\n", sizeof(bool));  // Ok
    printf("%zu\n", sizeof(a));     // Ok
    printf("%zu\n", sizeof(a ? true : false)); // Why 4?
    return 0;
}

Đầu ra ( GCC ):

1
1
4 // Why 4?

Nhưng ở đây,

printf("%zu\n", sizeof(a ? true : false)); // Why 4?

toán tử ternary trả về booleankiểu và sizeof bool1 byte trong C.

Vậy thì tại sao lại sizeof(a ? true : false)cho đầu ra bốn byte?


39
sizeof(true)sizeof(false)cũng là 4: ide.geekforgeek.org/O5jvuN
tkausl

7
Câu hỏi thú vị hơn ở đây sẽ là tại sao việc triển khai này "không nhất quán" ở chỗ nó rõ ràng được định nghĩa _Boollà có kích thước 1, nhưng không truefalse. Nhưng tiêu chuẩn không có gì để nói về điều đó như tôi có thể nói.

12
@FelixPalmen cùng lý do tại sao được đưa ra char a; sizeof(a) == 1sizeof('a') == sizeof(int)(bằng C). Đó không phải là về việc thực hiện, mà là về ngôn ngữ.
n. 'đại từ' m.

10
Bạn đã thử in sizeof(true)chưa? có lẽ nó sẽ làm cho nó rõ ràng hơn một chút (đặc biệt, nó sẽ trở nên rõ ràng rằng toán tử ternary là một cá trích đỏ).
n. 'đại từ' m.

4
@FelixPalmen true#define1 bởi stdbool.hvì vậy, đây là định nghĩa theo nghĩa đen.
n. 'đại từ' m.

Câu trả lời:


223

Đó là bởi vì bạn có #include <stdbool.h>. Tiêu đề đó xác định các macro truefalseđược 10, vì vậy câu lệnh của bạn trông như thế này:

printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?

sizeof(int) là 4 trên nền tảng của bạn.


21
"Đó là bởi vì bạn có #include <stdbool.h>" Không, không phải vậy. sizeof(a ? (uint8_t)1 : (uint8_t)0);cũng sẽ cho kết quả là 4. Quảng cáo số nguyên của ?:toán hạng là phần quan trọng ở đây, không phải kích thước của truefalse.
Lundin

9
@Lundin: Cả hai đều quan trọng. Như đã viết, loại đã intkhông có khuyến mãi. Lý do bạn không thể "sửa" nó là các chương trình khuyến mãi mặc định.
R .. GitHub DỪNG GIÚP ICE

5
@PeterSchneider Đây không phải là C ++. Đây là C. Trong C ++ truekhông phảifalse là macro; chúng là những từ khóa Chúng không được định nghĩa là và , nhưng là giá trị đúng và sai của loại. 10bool
Justin

5
@PeterSchneider Không, bạn đã học được vài điều về C ngày hôm nay. Đừng nhầm lẫn hai ngôn ngữ. Trong C ++, sizeof(true)là 1. bản demo .
Rakete1111

1
Đúng, trộn nó lên. Không đọc kỹ và bị sai bởi liên kết cppreference. Lỗi của tôi, cảm ơn bạn. Nhưng dù sao tôi cũng có cảm giác về c ++.
Peter Schneider

66

Ở đây, booleanloại trả về toán tử ternary ,

OK, có nhiều hơn thế!

Trong C, kết quả của việc này hoạt động ternary là loại int.[ghi chú bên dưới (1,2)]

Do đó, kết quả giống như biểu thức sizeof(int), trên nền tảng của bạn.


Lưu ý 1: Trích dẫn C11 , chương §7,18,Boolean type and values <stdbool.h>

[....] Ba macro còn lại phù hợp để sử dụng trong #if chỉ thị tiền xử lý. họ đang

true

mở rộng đến hằng số nguyên 1,

false

mở rộng thành hằng số nguyên 0, [....]

Lưu ý 2: Đối với toán tử có điều kiện, chương §6.5.15, ( nhấn mạnh của tôi )

Toán hạng đầu tiên được đánh giá; có một điểm thứ tự giữa đánh giá của nó và đánh giá toán hạng thứ hai hoặc thứ ba (tùy theo đánh giá nào). Toán hạng thứ hai chỉ được ước tính nếu giá trị thứ nhất so sánh bằng 0; toán hạng thứ ba chỉ được ước tính nếu giá trị thứ nhất bằng 0; kết quả là giá trị của toán hạng thứ hai hoặc thứ ba (tùy theo giá trị nào được đánh giá), [...]

Nếu cả hai toán hạng thứ hai và thứ ba có loại số học, loại kết quả sẽ được xác định bởi các chuyển đổi số học thông thường, chúng được áp dụng cho hai toán hạng đó, là loại kết quả.[....]

do đó, kết quả sẽ là kiểu nguyên và do phạm vi giá trị, các hằng số chính xác là kiểu int .

Điều đó nói rằng, một lời khuyên chung chung, int main()tốt hơn là int main (void)nên thực sự tuân thủ tiêu chuẩn.


@ user694733 umm..tại sao không? <stdbool.h>định nghĩa MACROS là loại int.. điều đó có sai không?
Sourav Ghosh

@BasileStarynkevitch OK, tôi thấy rằng bây giờ, điều này có vẻ thực sự sai, cập nhật ngay bây giờ.
Sourav Ghosh

58

Các nhà điều hành ternary là một cá trích đỏ.

    printf("%zu\n", sizeof(true));

in 4 (hoặc bất cứ điều gì sizeof(int)trên nền tảng của bạn).

Các giả định sau đây boollà từ đồng nghĩa với charhoặc loại tương tự có kích thước 1 và intlớn hơn char.

Lý do tại sao sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int)chỉ đơn giản là bởi vì truekhông một biểu hiện của loại bool. Đó là một biểu hiện của loại int. Nó là #defined như 1trongstdbool.h .

Không có giá trị của loại booltrong C cả. Mỗi giá trị như vậy ngay lập tức được thăng cấp int, ngay cả khi được sử dụng làm đối số sizeof. Chỉnh sửa: đoạn này không đúng, các đối số sizeofkhông được quảng bá int. Điều này không ảnh hưởng đến bất kỳ kết luận nào.


Câu trả lời tốt đẹp. Sau khi tôi đọc câu trả lời hiện tại được đánh giá cao nhất, tôi đã nghĩ rằng tất cả các câu nên đánh giá đến 4. Điều này đã làm mọi thứ rõ ràng. +1
Pedro A

5
Không phải là (bool)1một giá trị của loại bool?
Ben Voigt

printf("%u\n", sizeof((char) 1));in 1trên nền tảng của tôi trong khi printf("%u\n", sizeof(1));in 4. Điều này không có nghĩa là tuyên bố của bạn "Mọi giá trị như vậy ngay lập tức được thăng cấp lên int, ngay cả khi được sử dụng làm đối số cho sizeof" là sai?
JonatanE

Điều này không thực sự trả lời câu hỏi. Kích thước và loại truevv không thực sự quan trọng trong trường hợp ?:kể từ khi nó được tăng số nguyên lên intdù sao đi nữa. Đó là, câu trả lời nên giải quyết tại sao ?: cá trích đỏ.
Lundin

6
Tôi nghĩ rằng câu trả lời giải quyết vấn đề theo cách tốt nhất có thể. Bạn được chào đón để downvote hoặc cải thiện nó.
n. 'đại từ' m.

31

Về loại boolean trong C

Một kiểu boolean được giới thiệu khá muộn trong ngôn ngữ C, vào năm 1999. Trước đó, C không có kiểu boolean mà thay vào đó được sử dụng intcho tất cả các biểu thức boolean. Do đó, tất cả các toán tử logic như > == !vv trả intvề giá trị 1hoặc0 .

Nó đã được tùy chỉnh cho các ứng dụng để sử dụng các loại sản xuất tại nhà, chẳng hạn như typedef enum { FALSE, TRUE } BOOL;cũng có intcác loại kích cỡ.

C ++ có loại boolean rõ ràng và tốt hơn nhiều, boolkhông lớn hơn 1 byte. Trong khi các kiểu boolean hoặc biểu thức trong C sẽ có 4 byte trong trường hợp xấu nhất. Một số cách tương thích với C ++ đã được giới thiệu trong C với tiêu chuẩn C99. C sau đó có một kiểu boolean _Boolvà tiêu đề stdbool.h.

stdbool.hcung cấp một số khả năng tương thích với C ++. Tiêu đề này xác định macro bool(cùng cách viết với từ khóa C ++) mở rộng ra _Bool, một loại là loại số nguyên nhỏ, có khả năng lớn 1 byte. Tương tự, tiêu đề cung cấp hai macro truefalsecùng một cách viết với từ khóa C ++, nhưng có khả năng tương thích ngược với các chương trình C cũ hơn . Do đó truefalsemở rộng đến 10trong C và loại của họ làint . Các macro này không thực sự thuộc loại boolean như các từ khóa C ++ tương ứng.

Tương tự, đối với các mục đích tương thích ngược, các toán tử logic trong C vẫn trả về intcho đến ngày nay, mặc dù ngày nay C có kiểu boolean. Trong khi ở C ++, toán tử logic trả về a bool. Do đó, một biểu thức như sizeof(a == b)sẽ cho kích thước của một inttrong C, nhưng kích thước của một booltrong C ++.

Về toán tử điều kiện ?:

Toán tử điều kiện ?:là một toán tử kỳ lạ với một vài quirks. Đó là một sai lầm phổ biến để tin rằng nó tương đương 100% if() { } else {}. Không hẳn.

Có một điểm thứ tự giữa việc đánh giá toán hạng 1 và 2 hoặc 3. Các ?:nhà điều hành được đảm bảo chỉ đánh giá hệ 2 hoặc toán hạng thứ 3, vì vậy nó không thể thực hiện bất kỳ tác dụng phụ của các toán hạng không được đánh giá. Mã như true? func1() : func2()sẽ không thực thi func2(). Càng xa càng tốt.

Tuy nhiên , có một quy tắc đặc biệt nói rằng toán hạng thứ 2 và thứ 3 phải được loại hoàn toàn được thăng cấp và cân bằng với nhau bằng các chuyển đổi số học thông thường . ( Quy tắc quảng cáo ngầm định trong C được giải thích ở đây ). Điều này có nghĩa là toán hạng thứ 2 hoặc thứ 3 sẽ luôn lớn nhất bằng một int.

Vì vậy, nó không thành vấn đề truevà tình falsecờ thuộc loại intC vì biểu thức sẽ luôn cung cấp ít nhất kích thước của một intvấn đề.

Ngay cả khi bạn viết lại biểu thức thành nó vẫn sẽ trả về kích thước của một !sizeof(a ? (bool)true : (bool)false) int

Điều này là do quảng cáo kiểu ngầm thông qua các chuyển đổi số học thông thường.


1
C ++ không thực sự đảm bảo sizeof(bool)==1.
aschepler

1
@aschepler Không, nhưng thế giới thực bên ngoài tiêu chuẩn C ++ không đảm bảo điều đó. Đặt tên cho một trình biên dịch không phải là 1.
Lundin

Chào. Tôi nghĩ rằng câu trả lời này sẽ tốt hơn nếu không có phần đầu tiên. Phần thứ hai trả lời câu hỏi. Phần còn lại, trong khi thú vị, chỉ là tiếng ồn.
YSC

@YSC Điều này ban đầu được gắn thẻ C và C ++, vì vậy việc so sánh giữa các loại bool khác nhau của họ và lịch sử đằng sau chúng là cần thiết. Tôi nghi ngờ tôi đã viết phần đầu tiên nếu không có thẻ C ++. Tuy nhiên, người ta phải hiểu tại sao sizeof (bool) là 1 nhưng sizeof (false) là 4 trong C.
Lundin

21

Câu trả lời nhanh:

  • sizeof(a ? true : false) đánh giá 4 bởi vì truefalseđược định nghĩa <stdbool.h>theo 10tương ứng, vì vậy biểu thức mở rộng thành sizeof(a ? 1 : 0)biểu thức số nguyên với loại int, chiếm 4 byte trên nền tảng của bạn. Vì lý do tương tự, sizeof(true)cũng sẽ đánh giá 4trên hệ thống của bạn.

Tuy nhiên, lưu ý rằng:

  • sizeof(a ? a : a)cũng ước tính 4bởi vì toán tử ternary thực hiện các chương trình khuyến mãi số nguyên trên các toán hạng thứ hai và thứ ba của nó nếu đây là các biểu thức số nguyên. Điều tương tự tất nhiên xảy ra cho sizeof(a ? true : false)sizeof(a ? (bool)true : (bool)false), nhưng đúc toàn bộ biểu thức như boolhành vi như mong đợi : sizeof((bool)(a ? true : false)) -> 1.

  • cũng lưu ý rằng các toán tử so sánh đánh giá các giá trị boolean 1hoặc 0, nhưng có intkiểu : sizeof(a == a) -> 4.

Các toán tử duy nhất giữ bản chất boolean alà:

  • toán tử dấu phẩy: cả hai sizeof(a, a)sizeof(true, a)đánh giá 1tại thời điểm biên dịch.

  • toán tử gán: cả hai sizeof(a = a)sizeof(a = true)có giá trị là 1.

  • toán tử gia tăng: sizeof(a++) -> 1

Cuối cùng, tất cả những điều trên chỉ áp dụng cho C: C ++ có ngữ nghĩa khác nhau về boolloại, giá trị boolean truefalse, toán tử so sánh và toán tử ternary: tất cả các sizeof()biểu thức này ước tính 1trong C ++.


2
Câu trả lời hay mà thực sự quản lý để chỉ ra rằng nó không thực sự quan trọng thuộc loại nào truefalsebởi vì các ?:toán hạng sẽ được thăng cấp thành số nguyên int. Do đó sizeof(a ? (uint8_t)true : (uint8_t)false)cũng sẽ mang lại kết quả 4.
Lundin

Câu trả lời này bao gồm điểm quan trọng chính, giá trị được thăng hạng lênint
Chinni

1

Đây là một đoạn trích từ đó là những gì có trong nguồn

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

#else /* __cplusplus */

Có các macro truefalseđược khai báo lần lượt là 1 và 0.

tuy nhiên trong trường hợp này, kiểu này là kiểu của hằng số theo nghĩa đen. Cả 0 và 1 đều là hằng số nguyên phù hợp với một int, vì vậy kiểu của chúng là int.

sizeof(int)trong trường hợp của bạn là 4.


-3

Không có kiểu dữ liệu boolean trong C, thay vào đó các biểu thức logic đánh giá các giá trị nguyên 1khi đúng khác 0.

Biểu thức có điều kiện thích if, for, while, hoặc c ? a : bmong đợi một số nguyên, nếu số lượng không phải là zero nó được coi là truengoại trừ một số trường hợp đặc biệt, đây là một chức năng tổng hợp đệ quy trong đó ternary-nhà điều hành sẽ đánh giá truecho đến khi ntầm 0.

int sum (int n) { return n ? n+sum(n-1) : n ;

Nó cũng có thể được sử dụng để NULLkiểm tra một con trỏ, đây là một hàm đệ quy in nội dung của Danh sách liên kết đơn.

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
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.