Почему sizeof (a? True: false) дает выход из четырех байтов?
У меня есть небольшой фрагмент кода о операторе 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)
дает вывод четырех байтов?
Ответы
Ответ 1
Это потому, что у вас есть #include <stdbool.h>
. Этот заголовок определяет макросы true
и false
как 1
и 0
, поэтому ваше утверждение выглядит так:
printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?
sizeof(int)
- 4 на вашей платформе.
Ответ 2
Здесь тернарный оператор возвращает тип boolean
,
Хорошо, еще к этому!
В C результат этой тернарной операции имеет тип int
. [примечания ниже (1,2)]
Следовательно, результат будет таким же, как выражение sizeof(int)
, на вашей платформе.
Примечание 1: Цитирование C11
, глава §7.18, Boolean type and values <stdbool.h>
[....] Оставшиеся три макроса подходят для использования в директивах #if
для предварительной обработки. Oни являются
true
которая расширяется до целочисленной константы 1,
false
который расширяется до целочисленной константы 0, [....]
Примечание 2: для условного оператора, глава §6.5.15, (выделено мной)
Первый операнд оценивается; между его оценкой и точкой оценка второго или третьего операнда (в зависимости от того, что оценивается). Второй операнд оценивается только в том случае, если первое сравнивается не равным 0; третий операнд оценивается только в том случае, если первое сравнивается с 0; результат - это значение второго или третьего операнда (в зависимости от того, что оценивается), [...]
и
Если и второй, и третий операнды имеют арифметический тип, тип результата, который будет определяемые обычными арифметическими преобразованиями, были применены к этим двум операндам, является типом результата. [....]
следовательно, результат будет иметь тип integer и из-за диапазона значений константы будут точно типа int
.
Тем не менее, общий совет int main()
должен быть лучше int main (void)
, чтобы быть по-настоящему стандартным.
Ответ 3
Тернарный оператор - красная селедка.
printf("%zu\n", sizeof(true));
печатает 4 (или что-то еще sizeof(int)
на вашей платформе).
Далее предполагается, что bool
является синонимом для char
или аналогичного типа размера 1, а int
больше, чем char
.
Причина, по которой sizeof(true) != sizeof(bool)
и sizeof(true) == sizeof(int)
просто потому, что true
является not выражением типа bool
. Это выражение типа int
. Это #define
d как 1
в stdbool.h
.
В C вообще нет rvalues типа bool
. Каждое такое rvalue немедленно продвигается до int
, даже если используется в качестве аргумента для sizeof
. Изменить: этот абзац неверен, аргументы sizeof
не получают повышение до int
. Однако это не влияет на какие-либо выводы.
Ответ 4
Что касается булевого типа в C
Логический тип был введен довольно поздно на языке C в 1999 году. До этого C не имел логического типа, но вместо этого использовал int
для всех булевых выражений. Поэтому все логические операторы, такие как > == !
и т.д., Возвращают int
значения 1
или 0
.
Для приложений использовались домашние типы, такие как typedef enum { FALSE, TRUE } BOOL;
, которые также сводятся к int
-размерным типам.
С++ имел гораздо лучший и явный логический тип bool
, размер которого не превышал 1 байт. Хотя логические типы или выражения в C в худшем случае заканчиваются как 4 байта. Некоторая совместимость с С++ была введена на C со стандартом C99. C затем получил булев тип _Bool
, а также заголовок stdbool.h
.
stdbool.h
обеспечивает некоторую совместимость с С++. Этот заголовок определяет макрос bool
(то же самое, что и ключевое слово С++), которое расширяется до _Bool
, тип, который представляет собой небольшой целочисленный тип, вероятно, 1 байт большой. Аналогично, заголовок содержит два макроса true
и false
, одинаковое написание как ключевые слова С++, но с обратной совместимостью с более старыми программами на C. Поэтому true
и false
расширяются до 1
и 0
в C, а их тип int
. Эти макросы на самом деле не являются булевыми типами, как соответствующие ключевые слова С++.
Аналогично, для целей обратной совместимости логические операторы в C по-прежнему возвращают int
по сей день, хотя C теперь имеет тип boolean. В то время как в С++ логические операторы возвращают bool
. Таким образом, выражение, такое как sizeof(a == b)
, даст размер int
в C, но размер a bool
в С++.
Относительно условного оператора ?:
Условный оператор ?:
является странным оператором с несколькими причудами. Ошибочно полагать, что он на 100% эквивалентен if() { } else {}
. Не совсем.
Существует точка последовательности между оценкой 1-го и 2-го или 3-го операндов. Оператору ?:
гарантируется оценка только второго или третьего операнда, поэтому он не может выполнять никаких побочных эффектов операнда, который не оценивается. Код типа true? func1() : func2()
не выполнит func2()
. Пока что так хорошо.
Однако существует специальное правило, в котором говорится, что 2-й и 3-й операнды должны получать неявный тип, продвигаемый и сбалансированный друг против друга с помощью обычных арифметических преобразований. (Непонятные правила продвижения по типу в C, описанные здесь). Это означает, что 2-й или 3-й операнд всегда будет как минимум равным int
.
Таким образом, не имеет значения, что true
и false
имеют тип int
в C, потому что выражение всегда будет давать, по крайней мере, размер int
независимо от того.
Даже если вы перепишете выражение на sizeof(a ? (bool)true : (bool)false)
, оно все равно вернет размер int
!
Это связано с неявным продвижением типа посредством обычных арифметических преобразований.
Ответ 5
Быстрый ответ:
-
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
.
-
также отметим, что операторы сравнения вычисляют значения boolean 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: С++ имеет другую семантику относительно типа bool
, логических значений true
и false
, операторов сравнения и тернарного оператора: все эти выражения sizeof()
оценивают на 1
в С++.
Ответ 6
Вот фрагмент, из которого что-то включено в исходный
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#else /* __cplusplus */
Там макросы true
и false
объявлены как 1 и 0 соответственно.
однако в этом случае тип является типом литерала. Оба значения 0 и 1 являются целыми константами, которые вписываются в int, поэтому их тип - int.
а sizeof(int)
в вашем случае - 4.
Ответ 7
В C нет логического типа данных, вместо этого логические выражения оцениваются с целыми значениями 1
, когда true в противном случае 0
.
Условные выражения типа if
, for
, while
или c ? a : b
ожидают целое число, если число отличное от нуля, оно считается true
, за исключением некоторых особых случаев, здесь рекурсивная функция суммы в который тернарный оператор будет оценивать true
, пока n
не достигнет 0
.
int sum (int n) { return n ? n+sum(n-1) : n ;
Его также можно использовать для NULL
проверки указателя, здесь рекурсивная функция, которая печатает содержимое односвязного-списка.
void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }