Чому "sizeof (a? True: false)" дає вихід з чотирьох байтів?


133

У мене є невеликий фрагмент коду про sizeofоператора з потрійним оператором:

#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;
}

Вихід ( GCC ):

1
1
4 // Why 4?

Але ось,

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

потрійний оператор повертає booleanтип і sizeof boolтип - 1байт у C.

Тоді чому sizeof(a ? true : false)дається вихід у чотири байти?


39
sizeof(true)а sizeof(false)також 4: ide.geeksforgeeks.org/O5jvuN
tkausl

7
Більш цікавим питанням було б, чому ця реалізація є "непослідовною" тим, що вона, очевидно, визначає _Boolрозмір 1, але не trueі false. Але наскільки я можу сказати, стандарт не має нічого про це сказати.

12
@FelixPalmen та сама причина, чому вказано char a; sizeof(a) == 1і sizeof('a') == sizeof(int)(в С). Не про реалізацію, а про мову.
н. 'займенники' м.

10
Ви намагалися надрукувати sizeof(true)? можливо, це зробить тонкі трохи більш зрозумілими (зокрема, стане очевидним, що потрійний оператор - це червона оселедець).
н. 'займенники' м.

4
@FelixPalmen trueмає #defineбути 1, stdbool.hтому так, це буквальне визначення.
н. 'займенники' м.

Відповіді:


223

Це тому, що у вас є #include <stdbool.h>. Це заголовок визначає макроси true та falseбути, 1і 0тому ваше твердження виглядає так:

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

sizeof(int) є 4 на вашій платформі.


21
"Це тому, що у вас #include <stdbool.h>" Ні, це не так. sizeof(a ? (uint8_t)1 : (uint8_t)0);Тут було б також результат 4. Ціле просування ?:операндів є важливою частиною тут, а не розміром trueі false.
Лундін

9
@Lundin: Обидва важливі. Як було написано, тип вже intне має рекламної кампанії. Причиною ви не можете "виправити" це акції за замовчуванням.
R .. GitHub СТОП ДОПОМОГАТИ ДВІ

5
@PeterSchneider Це не C ++. Це C. В C ++, trueі неfalse є макросами; це ключові слова. Вони не визначені як та , а як істинні та хибні значення типу. 10bool
Джастін

5
@PeterSchneider Ні, ви дізналися щось про C сьогодні. Не плутай дві мови. У C ++, sizeof(true)це 1. демонстрація .
Rakete1111

1
Щоправда, змішав це. Не читав уважно і був введений в оману за допомогою cppreference-link. Моя провина, дякую. Але я все-таки маю таке відчуття щодо c ++.
Пітер Шнайдер

66

Тут booleanтип повернення потрійного оператора ,

Гаразд, тут є ще щось!

В C результат цієї потрійної операції має тип int. [примітки нижче (1,2)]

Отже, результат такий же, як вираз sizeof(int), на вашій платформі.


Примітка 1: Цитування C11 , глава §7.18,Boolean type and values <stdbool.h>

[....] Решта три макроси підходять для використання в #ifдирективах щодо попередньої обробки. Вони є

true

яке розширюється до цілої постійної 1,

false

яке розширюється до цілої постійної 0, [....]

Примітка 2: Для умовного оператора, глава §6.5.15, ( наголос мій )

Перший операнд оцінюється; між його оцінкою та оцінкою другого чи третього операнду існує точка послідовності (залежно від того, що оцінюється). Другий операнд оцінюється лише в тому випадку, якщо перший порівнює нерівне з 0; третій операнд оцінюється лише в тому випадку, якщо перший порівнюється рівним 0; результат - значення другого або третього операнда (залежно від того, що оцінюється), [...]

і

Якщо і другий, і третій операнди мають арифметичний тип, тип результату, який визначався б звичайними арифметичними перетвореннями, якби вони застосовувалися до цих двох операндів, - це тип результату.[....]

отже, результат буде цілим типом, а через діапазон значень константи мають саме тип int .

Зважаючи на це, загальна порада int main()має бути найкращою, int main (void)щоб відповідати стандартам.


@ user694733 гмм ... чому ні? <stdbool.h>визначає тип intMACROS типу .. це неправильно?
Sourav Ghosh

@BasileStarynkevitch Добре, я бачу, що зараз, здається, це неправильно, оновлено зараз.
Sourav Ghosh

58

Потрійний оператор - це червона оселедець.

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

друкує 4 (або все, що sizeof(int)є на вашій платформі).

Далі передбачається, що boolє синонімом charрозміру 1 або подібного типу і intє більшим за char.

Причина, чому sizeof(true) != sizeof(bool)і sizeof(true) == sizeof(int)просто тому true, що не є виразом типу bool. Це вираз типу int. Це #defined як 1вstdbool.h .

У boolС взагалі немає оцінок типу . Кожне таке оцінювання негайно просувається int, навіть якщо воно використовується як аргумент sizeof. Редагувати: цей абзац не відповідає дійсності, аргументи, до sizeofяких не слід рекламувати int. Однак це не впливає на жоден із висновків.


Гарна відповідь. Після того, як я прочитав відповідь, що зараз найбільше підтримує, я думав, що всі твердження повинні оцінюватися до 4. Це очистило речі. +1
Педро

5
Це не (bool)1рецензія типу bool?
Ben Voigt

printf("%u\n", sizeof((char) 1));друкує 1на моїй платформі, тоді як printf("%u\n", sizeof(1));друкує 4. Чи це не означає, що ваше твердження "Кожне таке оцінювання негайно просувається до int, навіть коли воно використовується як аргумент до sizeof" є помилковим?
JonatanE

Це насправді не відповідає на питання. Розмір та тип trueтощо насправді не мають значення, ?:оскільки вони так intчи інакше рекламуються . Тобто відповідь має стосуватися, чому ?: саме червона оселедець.
Лундін

6
Я думаю, що відповідь вирішує питання найкращим чином. Запрошуємо вас зняти або покращити його.
н. 'займенники' м.

31

Що стосується булевого типу в С

Булевський тип був введений досить пізно мовою С, в 1999 році. До цього C не мав булевого типу, а натомість використовувався intдля всіх булевих виразів. Тому всі логічні оператори, такі як > == !etc, повертають intзначення 1або0 .

У додатках було звичайно використовувати домашні типи, такі як typedef enum { FALSE, TRUE } BOOL;, яке також зводиться до int-розмірних типів.

C ++ мав набагато кращий і явніший булівський тип bool, який був не більший за 1 байт. У той час як булеві типи або вирази в C в гіршому випадку закінчуються як 4 байти. Деякий спосіб сумісності з C ++ був введений в C зі стандартом C99. Потім C отримав булевий тип, _Boolа також заголовок stdbool.h.

stdbool.hзабезпечує деяку сумісність із C ++. Це заголовок визначає макрос bool(те саме написання, що і ключове слово C ++), який розширюється на _Boolтип, який є малим цілим типом, ймовірно, на 1 байт. Крім того , заголовок містить два макроси trueі false, таке ж написання , як ключові слова C ++, але зі зворотним сумісністю з більш старими програмами C . Тому trueі falseрозширюватися 1і 0в C і їх типint . Ці макроси насправді не бульового типу, як відповідні ключові слова C ++.

Аналогічно, для цілей зворотної сумісності логічні оператори в C досі повертають a intдонині, незважаючи на те, що C нині набув булевого типу. Перебуваючи в C ++, логічні оператори повертають a bool. Таким чином, такий вираз sizeof(a == b)дасть розмір а intв С, але розмір а boolв С ++.

Щодо умовного оператора ?:

Умовний оператор ?:- дивний оператор з парою примх. Поширена помилка вважати, що це 100% еквівалентно if() { } else {}. Не зовсім.

Між оцінкою 1-го та 2-го або 3-го операндів існує точка послідовності. ?:Оператор гарантовано тільки оцінити або 2 - го або 3 - го операнда, тому він не може виконати будь - які побічні ефекти операнда, що не оцінюється. Код як би true? func1() : func2()не виконується func2(). Все йде нормально.

Однак існує спеціальне правило, яке вказує на те, що 2-й і 3-й операнди повинні неявно набирати тип і сприяти їх рівновазі звичайними арифметичними перетвореннями . ( Неявні правила просування типу в C пояснюються тут ). Це означає, що 2-й або 3-й операнд завжди буде принаймні таким же великим, як і int.

Отже, це не має значення, trueі false, мабуть, має тип intC, оскільки вираз завжди надаватиме принаймні розмір intзначення.

Навіть якби ви переписали вираз до нього, він все одно поверне розмір !sizeof(a ? (bool)true : (bool)false) int

Це відбувається через неявне просування типу за допомогою звичайних арифметичних перетворень.


1
C ++ насправді не гарантує sizeof(bool)==1.
aschepler

1
@aschepler Ні, але реальний світ поза стандартом C ++ все ж гарантує це. Назвіть одного компілятора, де його немає 1.
Лундін

Привіт. Я думаю, що ця відповідь була б кращою без її першої частини. Друга частина відповідає на питання. Решта, хоча цікаво, - це лише шум.
YSC

@YSC Це спочатку було позначено як C, так і C ++, тому порівняння між різними типами булів та історією за ними було необхідним. Сумніваюся, я написав би першу частину, якби не тег C ++. Однак треба розуміти, чому розмір (bool) дорівнює 1, але розмірof (false) дорівнює 4 в C.
Лундін,

21

Швидка відповідь:

  • sizeof(a ? true : false)оцінює до 4тому, що trueі falseвизначається <stdbool.h>як 1і 0відповідно, тому вираз розширюється на sizeof(a ? 1 : 0)яке є цілим виразом з типом int, що займає 4 байти на вашій платформі. З тієї ж причини sizeof(true)також оцінювали б 4у вашій системі.

Зауважте, що:

  • sizeof(a ? a : a)також оцінює 4тому, що потрійний оператор виконує цілі промоції на своєму другому та третьому операндах, якщо це цілі вирази. Те ж саме, звичайно , відбувається з- за sizeof(a ? true : false)і sizeof(a ? (bool)true : (bool)false), але лиття ціле вираз , як boolповодиться , як і очікувалося: sizeof((bool)(a ? true : false)) -> 1.

  • Також зверніть увагу , що оператори порівняння оцінки для логічних значень 1або 0, але мають intтипу: sizeof(a == a) -> 4.

Єдиними операторами, які зберігають булеву природу, aбули б:

  • оператор з комами: обидва sizeof(a, a)і sizeof(true, a)оцінюють до 1часу компіляції.

  • оператори присвоєння: обидва sizeof(a = a)і sizeof(a = true)мають значення 1.

  • збільшення операторів: sizeof(a++) -> 1

Нарешті, все вищесказане стосується лише C: C ++ має різну семантику щодо boolтипу, булевих значень trueта falseоператорів порівняння та потрійного оператора: всі ці sizeof()вирази оцінюються 1у C ++.


2
Хороша відповідь, що насправді вдається зазначити, що насправді не має значення, який тип trueі які falseє, тому що ?:операнди отримали б ціле число, яке просунулося б int. Таким чином sizeof(a ? (uint8_t)true : (uint8_t)false), також вийде 4.
Лундін

Ця відповідь охоплює головний важливий момент, про який можна int
підвищити

1

Ось фрагмент, з якого є те, що включено до джерела

#ifndef __cplusplus

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

#else /* __cplusplus */

Є макроси trueі falseоголошуються як 1 і 0 відповідно.

однак у цьому випадку тип - це тип буквальних констант. І 0, і 1 є цілими константами, які вміщуються в int, тому їх тип - int.

а sizeof(int)у вашому випадку - 4.


-3

У C немає ніякого булевого типу даних, натомість логічні вирази оцінюють до цілих значень, 1якщо істинно інакше 0.

Умовні вирази , як if, for, whileабо c ? a : bочікувати ціле число, якщо число не дорівнює нулю це вважається trueза винятком деяких особливих випадків, ось рекурсивна функція суми , в якій потрійний-оператор буде оцінювати trueдо nдосяжності 0.

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

Він також може бути використаний для NULLперевірки вказівника, ось рекурсивна функція, яка друкує вміст Singly-Linked-List.

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.