C Booleans
Very often, in programming, you will need a data type that can only have one of two values, like:
- YES / NO
- ON / OFF
- TRUE / FALSE
For this, C has a bool data type, which is known as booleans.
Booleans represent values that are either true or false .
Boolean Variables
In C, the bool type is not a built-in data type, like int or char .
It was introduced in C99, and you must import the following header file to use it:
A boolean variable is declared with the bool keyword and can only take the values true or false :
Before trying to print the boolean variables, you should know that boolean values are returned as integers:
- 1 (or any other number that is not 0) represents true
- 0 represents false
Therefore, you must use the %d format specifier to print a boolean value:
Example
// Create boolean variables
bool isProgrammingFun = true;
bool isFishTasty = false;
// Return boolean values
printf("%d", isProgrammingFun); // Returns 1 (true)
printf("%d", isFishTasty); // Returns 0 (false)
However, it is more common to return a boolean value by comparing values and variables.
Comparing Values and Variables
Comparing values are useful in programming, because it helps us to find answers and make decisions.
For example, you can use a comparison operator, such as the greater than ( > ) operator, to compare two values:
Example
From the example above, you can see that the return value is a boolean value ( 1 ).
You can also compare two variables:
Example
In the example below, we use the equal to ( == ) operator to compare different values:
Example
You are not limited to only compare numbers. You can also compare boolean variables, or even special structures, like arrays (which you will learn more about in a later chapter):
Example
bool isHamburgerTasty = true;
bool isPizzaTasty = true;
// Find out if both hamburger and pizza is tasty
printf("%d", isHamburgerTasty == isPizzaTasty);
Remember to include the <stdbool.h> header file when working with bool variables.
Real Life Example
Let’s think of a "real life example" where we need to find out if a person is old enough to vote.
In the example below, we use the >= comparison operator to find out if the age ( 25 ) is greater than OR equal to the voting age limit, which is set to 18 :
Example
int myAge = 25;
int votingAge = 18;
printf("%d", myAge >= votingAge); // Returns 1 (true), meaning 25 year olds are allowed to vote!
Cool, right? An even better approach (since we are on a roll now), would be to wrap the code above in an if. else statement, so we can perform different actions depending on the result:
Example
Output «Old enough to vote!» if myAge is greater than or equal to 18 . Otherwise output «Not old enough to vote.»:
int myAge = 25;
int votingAge = 18;
if (myAge >= votingAge) <
printf("Old enough to vote!");
> else <
printf("Not old enough to vote.");
>
Типы данных в С — bool, boolean и enum: сравнение и их возможности
Молодые программист ы п ри изучении языка программирования С ч асто встречают такие термины , как «boolean», «bool», «enum», но не всегда понимают , что это и когда их использовать. Сегодня мы исправим ситуацию и поговорим об этих терминах.
«Boolean» и «bool» — это термины, обозначающее одно и то же. Они указывают на то, что тип данных принадлежит к логическому типу. «Bool» — это сокращение от «boolean». Используется непосредственно в коде, когда программисту нужно взаимодействовать с логическим типом данных. Термин «boolean» чаще используется в разговоре, когда нужно указать, что речь идет именно о логически х ( булевых) данных.
Термин «enum» относится к перечисляемым типам данных. В числе перечисляемых типов данных могут быть строки или числа. Это довольно специфический идентификатор.
Теперь давайте о становимся на каждом термине и типе данных немного по подробнее.
«Boolean», «bool» в С — что это такое?
-
«true», оно же «1» или «истина»;
-
«false», оно же «0» или «ложь».
Перечисляемый тип данных «enum»
-
«WinterMonth» — это идентификатор перечисления, имя идентификатора всегда начинается с большой буквы;
-
«DECEMBER, JANUARY, FEBRUARY» — это перечислители, они всегда пишутся заглавными буквами ; перечислители не могут повторяться в разных перечислениях одного кода;
-
в конце перечисления всегда стоит точка с запятой;
-
каждому перечислителю в автоматическом режиме присваивается целочисленный идентификато р ( значение), начиная с «0», то есть: «DECEMBER» — «0», «JANUARY» — «1», FEBRUARY — «2»;
-
если нужно, тогда можно каждому перечислителю задать собственный идентификатор, например , это будет выглядеть так: «enum WinterMonth
;».
Заключение
Теперь вы познакомились с такими терминами, как «boolean», «bool» и «enum», и знаете , что это такое и к какому типу данных относится. Часто эти два типа данных конкурируют между собой, потому что предлагают п рограммист у осуществить программный выбор между значениями. Проблема в том, что «boolean» позволяет выбирать только между «true» и «false» , а это два взаимоисключающих состояния. Поэтому , если вы уверены, что у объекта может быть только 2 состояния, тогда этот тип значений актуально использовать. Например, как в нашем примере со сливой — она либо фрукт, либо нет.
Однако бывают такие случаи, когда состояния у объекта меняются или расширяются. В таких случаях рекомендуют использовать конструкцию «enum», потому что с «boolean» можно попасть в трудную ситуаци ю . В следующих статьях мы обязательно разберем такую ситуацию.
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Boolean in C
Since the computers operate on 0’s(False) and 1’s(True) computer logic is also expressed in boolean terms and all the complex logic of computers and digital systems is evaluated by using boolean algebra to take the particular decisions. So through this article, we will discuss the significance of Boolean in context with one of the most popular computer languages C.
Scope
- We will understand what are boolean values in C .
- Header files required to use boolean values in C .
- Also understand what are boolean logical operators in C and how to use them.
Why do We Need Boolean Values?
Computers and other Digital Systems only think in terms of ON(True) or OFF(False) , whereas we humans use a very diverse set of symbols in our daily life apart from these two terms. But when there comes a situation to make a decision, we only think in terms of Yes(True) or No(False) statements, which is nothing but a Boolean. Yes, you heard right, it’s Boolean. Boolean or boolean logic is a subset of algebra used for creating True or False statements. The term Boolean Algebra is named after the great mathematician George Boole. Hence, any kind of logic, expressions, or work theories by George Boole is considered Boolean .
Boolean Data Type in C
In C the terminology of boolean is associated with data type and Boolean is termed as one of the data types in the C Standard Library. This data type stores one of the two possible values denoted by true or false, which represents two truth values of logic and Boolean Algebra. All non-zero values are treated as true, while 0 is treated as false .
Though the boolean only stores true or false values, they are really very important in programming because they allow us to control the flow of code in different situations. In C, the Boolean data type can be invoked after including the "stdbool.h" header file. It means the C program will give a compilation error if we directly try to use boolean data type without including the stdbool.h header, whereas in C++, we do not have to include any extra headers .
Syntax to Declare Boolean Data Types in C:
To declare a boolean data type in C, we have to use a keyword named bool followed by a variable name.
Here, bool is the keyword denoting the data type and var_name is the variable name.
A bool takes in real 1 bit, as we need only 2 different values(0 or 1). So the sizeof (var_name) will give the result as 1 i.e. 1byte is required to store a boolean value and other 7 bits will be stuffed with 0 values.
Now let’s see a small example to understand the application of boolean data type in C.
Example of Boolean in C ( using stdbool.h header ):
In the above example, we have included the stdbool.h header file as we are using the bool type variable in our program, then we have declared a variable x of type boolean using bool and initialized it with value false. After that, we applied the condition checks using the if-else block to determine if the value of variable x is true or false.
What if we forgot the name of the header file to include for using boolean data type or what if we don’t want to include any extra header in our program but want to use boolean data type?
Well, we know that C doesn’t provide us with a boolean as a predefined data type. In such a scenario, we will have to create our custom data type, which will behave the same as shown in the previous example. To do this we can leverage the power of keyword typedef and enumeration ( enum ) in C.
Let’s understand this with an example.
Example of Boolean in C ( using typedef ):
Isn’t it simple? Let’s try to understand what we have implemented in the above example.
enum (enumeration) is a user-defined data type in C used to assign names to integer constants. In our case, we have assigned false to constant 0 state and true to constant 1 state using enum .
The typedef keyword is used to give a symbolic name to the type and is automatically interpreted by the compiler. In our case, we have assigned it as a bool_enum.
Hence, now we can use this custom type bool_enum which will behave the same as that of the boolean data type from the stdbool.h header file.
Boolean Arrays in C:
Like normal arrays, we can also create the boolean arrays using the data type bool from stdbool.h header file in C. The boolean array can store multiple true or false values for each element and all elements and can be accessed by using indexes.
Let’s see a small example to declare, initialize and print all elements from a boolean array. Through this example, we will try to initialize true value to all even indexed elements and false to all odd indexed elements.
In the above example, we have declared the boolean array and initialized all even index elements with true values and odd index elements with false values. Then we tried accessing those values based on indexes and tried printing them to the console.
Boolean and Logical Operators:
The Boolean data type when used with conditional statements like if..else ladders or simple if..else gives us the opportunity to choose specific actions by changing the control flow depending on the specified Boolean conditions (true or false) . At a time of evaluating conditions using if statements, it is often helpful to be able to do multiple comparisons at one time to limit the number of if statements used in our code, which allows us to write cleaner, concise, and more readable code .
Hence, if we want to perform multiple comparisons at one time, we need to understand how our computer interprets true and false values. When our computer encounters true or false, it assigns them numeric values of 1 or 0 respectively. Then the computer applies a set of logic based on Boolean Algebra. Boolean Algebra sets out the rules of what results to expect when combining multiple boolean logics with operators.
While performing Boolean logic, the expression on the left is evaluated, followed by the expression on the right. The two expressions are finally evaluated in the context of the logical operator between them. The return value is of Boolean type and is based on the operator type used.
There are Three Types of Logical Operators in the C Language:
We have already seen that Operators need some boolean conditions or boolean results to act upon. So for more clarity, we will assume set A and set B represent two independent boolean conditions or boolean results, and we will use them to understand the behavior of the boolean operators.
1. && (AND) Operator in C: The && (AND) operator is C also known as logical conjunction and requires both left-side expression and right-side expression to be true for the result to be true. All other cases results are false. This is logically the same as the intersection of two sets.
The truth table for the && (AND) Operator is given below,
Where A denotes the expression on the left side of the operator and B denotes the expression on the right side of the operator.
2. || (OR) Operator in C: The || (OR) operator in C requires only one of the boolean logic to be true for the result to be true. This is equivalent to the union of two sets.
The truth table for the || (AND) Operator is given below,
Where A denotes the expression on the left side of the operator and B denotes the expression on the right side of the operator.
Short-Circuiting:
There is a concept that is closely associated with the && (AND) and || (OR) operators named Short-Circuiting. It is a compiler optimization technique to avoid evaluating an unnecessary expression. As expressions are evaluated from left to right, there are some expressions that are calculated certainly by only evaluating parts of the expression. This technique detects such expressions and helps the compiler to achieve possible optimization.
For Example: In C++, there are possibilities of short-circuiting at a time of evaluating && (AND) and || (OR) operators. At the time of evaluating && (AND) operator if the expression on the left-hand side of the operator gives a false result, then irrespective of the values of the right-hand side the boolean expression will always give a false as the final result. So, in this situation evaluation of the right-hand side is avoided by the compiler.
Similarly, in the case of the || (OR) operator when the left hand evaluates to true, the result of the expression will always be true irrespective of the value of the right-hand side of the operator.
3. ! (NOT) Operator: The ! (NOT) Operator in C is used to negate the boolean value used after it. It only requires a single boolean value as an expression.
Example:
The truth table for the || (AND) Operator is given below,
Now let’s try to use these logical operators with booleans in C using a simple example.Now let’s try to use these logical operators with booleans in C using a simple example.
In the above example, we have seen how various boolean operators like AND, OR, and NOT evaluate the boolean values.
C и C++: межъязыковые интерфейсы
Как известно, C и C++ — это родственные языки между которыми есть много общего. Но их пути, с годами, расходятся всё сильнее. В общих чертах дело обстоит так: код, написанный на одном из этих языков, не может быть скомпилирован под видом кода, написанного на другом. Этому мешает множество больших и маленьких различий между языками. Причём, речь идёт не только о синтаксических различиях. Некоторые общие синтаксические конструкции могут иметь разную семантику. Поэтому обычно нет никакого смысла в том, чтобы компилировать код, написанный на C, с помощью C++-компилятора. Не стоит доверять тем, кто утверждает обратное.
Правда, есть одна сфера, где обычно наблюдается согласие между C и C++. Это — ABI (Application Binary Interface, двоичный интерфейс приложений). Структуры данных и функции одного языка могут быть, в той или иной мере, использованы в другом языке. C и C++, кроме того, достаточно сильно пересекаются в области спецификаций интерфейсов, вследствие чего один и тот же заголовочный файл можно использовать из кода, написанного на обоих языках.

В этом материале я постараюсь собрать то общее, что есть у C и C++ и предложу некоторые рекомендации, которые позволят достаточно хорошо сочетать эти языки. Это, правда, будет всего лишь рассказ, иллюстрирующий точку зрения C-программиста, который хочет создавать интерфейсы для C++.
Типы данных
В C и C++ используется один и тот же набор базовых типов данных и конструкций, которые можно применять и там и там. А вот при работе с некоторыми типами нужно учитывать то, что в них присутствуют небольшие различия.
Целочисленные типы — такие, как char , short , int , long в обоих языках имеют схожие представление и семантику. Но нужно знать о том, что у типа bool (или _Bool ) и у перечислений есть некоторые особенности, о которых мы поговорим ниже.
Все типы для чисел с плавающей запятой имеют одно и то же представление. При работе с ними используется одинаковый синтаксис. Это — float , double , и, возможно, long double . Но синтаксис комплексных типов в C и C++ различается. В C имеется нечто вроде спецификатора, указывающего на реальный базовый тип, а в C++ для описания таких типов используются шаблоны.
Массивы имеют одинаковый синтаксис и представление. Но C позволяет менять размер массива, давая возможность работать с так называемыми массивами переменной длины (Variable Length Arrays, VLA).
Типы struct и union , если в них не объявляются члены-функции, имеют одно и то же представление. В C++ их называют простыми структурами данных (Plain Old Data structures, POD).
Атомарные типы имеют одно и то же представление и семантику, но разный синтаксис. В C++ используются шаблоны. В C применяются квалификаторы и спецификаторы типов.
▍Логический тип данных
Логический тип данных в C «официально» называется _Bool , но существует удобный макрос, в котором объявлено ключевое слово bool , указывающее на этот тип. На самом деле, эта конструкция была создана только для обеспечения обратной совместимости с кодом, который был написан до введения логического типа. Её вполне могут убрать из будущих версий стандарта C. В C++ в использовании _Bool особого смысла нет, выглядит эта конструкция нехорошо и представляет собой введение в C++-код возможности C, которая является временной (хотя в таком статусе она уже пребывает очень и очень долго).
Поэтому легче всего для организации работы с логическими значениями просто пользоваться bool и при этом обращать внимание на то, чтобы C видел бы соответствующий заголовочный файл. Сделать это несложно:
Как уже было сказано, подключать этот заголовочный файл в C++ не имеет никакого смысла.
▍Перечисления
Простые перечисления должны обрабатываться в C и C++ одинаково. Константы перечисления имеют одинаковые значения, но разные типы. В C это — тип int , в C++ — это тип самого перечисления.
До тех пор, пока константы используются ради их значений, всё должно работать хорошо. Но если попытаться воспользоваться переменными или параметрами функций, имеющих перечисляемый тип, начнутся сложности. В C и C++ используются разные правила для неявного преобразования значений к таким типам и для преобразования значений таких типов к другим типам. Поэтому лучше их в таком качестве не использовать.
▍Атомарные типы
В C++ атомарный вариант некоего базового типа описывают в виде шаблона:
В C имеется два варианта объявления подобных типов:
В коде, который подойдёт и для C и для C++, можно пользоваться вторым из предыдущих двух вариантов:
▍Комплексные типы
В C++ комплексные типы, опять же, объявляют в виде шаблонных типов:
В C эквивалент этой конструкции выглядит так:
Оба языка гарантируют то, что эти типы представлены двумя последовательно расположенными объектами базового типа. Первый — для действительной части комплексного числа, второй — для мнимой.
К сожалению, в данном случае не существует синтаксической конструкции, подобной спецификатору _Atomic , о котором мы говорили выше. Это позволило бы пользоваться простым макросом. С другой стороны, существует не так много комплексных типов. Поэтому спасти положение может простое объявление таких типов прямо в коде программы:
Кроме того, нужно учитывать то, что код, в котором применяются комплексные типы C и C++, должен использовать идентификатор I только для указания комплексного корня из -1.
Объекты
Совместимость C и C++ на уровне ABI означает, что объекты с полями любых типов, общих для этих языков, имеют одно и то же представление. То есть — одинаковое размещение в памяти данных этих объектов и их одинаковую интерпретацию. С синтаксической точки зрения именованные объекты — то есть — переменные и параметры функций, объявляются одинаково. В противном случае сама идея спецификации общего интерфейса была бы безнадёжной.
▍Временные объекты
Надо отметить, что C и C++ очень сильно различаются в используемом в них понятии неименованных, временных объектов. В C существует два вида временных объектов:
- Возвращаемые значения функций, которые содержат массивы, представляют собой временные объекты, что позволяет обращаться к элементам массива с использованием механизмов адресной арифметики. Подобные временные объекты неизменяемы и прекращают существовать после того, как вычисление выражения, содержащего вызов функции, завершается.
- Составные литералы — временные объекты, которые создают явным образом. Они работают как переменные, объявленные в текущей области видимости, к ним обычно применимы все правила, применимые к подобным переменным.
Поэтому временные объекты в интерфейсах, как правило, лучше не использовать в тех случаях, когда они могли бы применяться в C для передачи адреса объекта функции, которая вернёт этот адрес для дальнейшего использования в текущей области видимости.
Мы ещё вернёмся к этой теме в разделах о списках аргументов переменной длины и о макросах.
▍Объекты с квалификатором const
В C++ объекты с квалификатором const можно помещать в заголовочные файлы, что приводит к тому, что они ведут себя как константы базового типа.
Эта конструкция (даже без constexpr ) не разрешена в C, так как её использование приведёт к объявлению объекта fortytwo во всех .o-файлах, а это приведёт к нарушению правила одного определения. Если, так сказать, сэмулировать эту возможность, объявив объект с использованием ключевого слова static , это приведёт к следующим последствиям:
- Будет создано несколько копий объекта, размещённых в разных местах памяти. Программы, которые сравнивают указатели на подобные объекты, могут работать неправильно.
- В C объекты, объявленные с ключевым словом static , нельзя использовать из функций, объявленных с ключевым словом inline .
Для структурных типов нет единого решения этой проблемы. В C используются составные литералы в макросе, в C++ применяется глобальный объект с квалификатором const .
Функции
Если речь идёт о функциях, относящихся к тем общим для C и C++ типам, о которых мы говорили выше, то на некоей платформе ABI вызова таких функций должен быть одинаковым. Это не зависит от языка, через который мы обращаемся к интерфейсу. Тут применяются одинаковые правила представления параметров функции и возвращаемых значений в аппаратных регистрах или в стеке. Первое важное различие между C и C++ заключается в том, что в C++ есть механизм перегрузки функций. Поэтому должно выполняться преобразование типов аргументов во внешней функции — если только не будет указано, что делать этого не нужно. Вот распространённая конструкция для реализации такого поведения:
Здесь имеются две C++-зоны, окружающие спецификацию общего интерфейса, объявляющего функцию с использованием ключевого слова extern с языковым интерфейсом C. Макрос __cplusplus при использовании любого C-компилятора гарантированно окажется необъявленным, а при использовании любого C++-компилятора — объявленным.
▍Функции без параметров
В C интерфейс функции, который объявляется с пустым списком параметров, на самом деле не имеет прототипа. Такая функция может принимать любое количество параметров (почти) любых типов. Существуют особые правила о том, как аргументы подобных функций преобразуются на вызывающей стороне.
Функция, которая действительно не принимает никаких аргументов, должна быть определена, в результате, особым образом. В частности, с использованием void в списке параметров. Например — это функция toto из вышеприведённого примера.
▍Функции со списком параметров переменной длины
Вот распространённая конструкция, используемая в C для описания функций, принимающих 2-мерные массивы:
В C++ нет синтаксических конструкций, поддерживающих эту возможность. Поэтому мы не можем пользоваться подобными функциями в описаниях интерфейсов между C и C++.
В теории, правда, C++ может использовать и подобные функции, так как ABI этой функции представляет собой два значения size_t и указатель на значение double . Информация о типе матрицы в C собирается в начале выполнения функции, у вызывающей стороны нет ничего, что она могла бы предоставить функции в дополнение к аргументам.
У нас может возникнуть желание предоставить «фиктивный» интерфейс для C++, которому нужно лишь значение типа double , но подобное, при неправильном использовании функции, может легко привести к негативным последствиям. Лучше всего создать небольшую обёртку, которая принимает подходящий шаблон типа vector .
▍Параметры, представленные многомерными массивами с квалификатором const
В C и C++ используются разные правила совместимости типов с различными квалификаторами. В C функцию с параметром, представленным 2-мерным массивом, объявленным с квалификатором const , нелегко вызвать с аргументом, объявленным без const . В межъязыковых интерфейсах этим лучше не пользоваться. Правда, можно пользоваться указателями на сущности, объявленные с использованием const .
▍Квалификатор restrict и псевдонимы
В C и C++ используются разные правила работы с псевдонимами. Так и должно быть из-за имеющейся в C++ концепции ссылки. Это значит, что следует проявлять большую осторожность в принятии решения о том, какими свойствами должен обладать указатель. В C есть возможность объявлять указатели с квалификатором restrict . Это приводит к тому, что к объекту, адрес которого хранит указатель, можно обращаться только посредством этого указателя. Это — мощная возможность, которая налагает важные ограничения на сторону, вызывающую функцию.
В C++ нет механизма, аналогичного этому. Часто по этому поводу выдвигают рекомендацию, в соответствии с которой при использовании C++ нужно просто объявить restrict в виде макроса, ничем не заменяемого. Но из-за этого теряется смысл информирования того, что вызывает функцию, о необходимости внимательно следить за тем, что передаётся функции, передавая разные аргументы в разные параметры.
Постарайтесь, если возможно, не пользоваться этим в межъязыковых интерфейсах. Если же без этого не обойтись — тщательно документируйте тот факт, что аргументы функции должны быть различными.
▍Функции, объявленные с ключевым словом inline
Семантика ключевого слова inline немного отличается в C и C++, но обычно, соблюдая осторожность, им можно пользоваться. Разница заключается в создании экземпляра функции в том случае, когда компоновщику нужна её копия. C++ занимается этим сам, а в C задача по предоставлению системе в точности одного экземпляра соответствующего кода ложится на программиста. Такой код должен располагаться в одном из связанных друг с другом объектных файлов. Поэтому, пользуясь этой возможностью, нужно проконтролировать, чтобы библиотека, реализующая интерфейс, предоставляла бы подобный код.
Но функции, объявленные с ключевым словом inline , это, в первую очередь, функции. Поэтому к ним применимо всё вышесказанное о различиях между C и C++. Если вы пользуетесь этой возможностью — постарайтесь сделать функции как можно меньше и переложите большую часть реализации их внутренних механизмов на возможности одного из языков.
▍Вариадические функции
Вариадические функции — это сложная тема. При работе с ними применяются непростые правила по преобразованию (продвижению) типов аргументов, у них нет внутреннего механизма, позволяющего узнать о количестве полученных аргументов. Не стоит создавать новые интерфейсы, использующие эту возможность. В результате использование этой возможности стоит ограничить несколькими стандартными функциями библиотеки C — вроде printf или scanf .
Оба языка имеют возможности, способные, в большинстве случаев, заменить вариадические функции. Но, конечно, использование вариадических шаблонов C++ выходит за рамки создания межъязыковых интерфейсов с C. Обычно в случаях, когда речь идёт о списке аргументов одного и того же типа, при объявлении которых используется квалификатор const , в промежуточных вызовах макроса может использоваться параметр, представленный временным массивом.
▍Универсальные интерфейсы функций
В C и C++ используются диаметрально противоположные стратегии при реализации универсальных интерфейсов функций. В C++ имеется механизм перегрузки функций и аргументы, применяемые по умолчанию. В C есть первичные выражения _Generic , для реализации которых используются макросы. Механизмы, используемые в C, нелегко расширять, то есть — можно объединить лишь функции для известного списка типов. Если нужно поддерживать новый тип — нужно изменить выражение _Generic или макрос.
Тут у C и C++ не особенно много общего. Поэтому, если нужно реализовать подобную возможность, рассчитанную на оба языка, нужно реализовывать её по-разному для каждого из них.
В качестве достаточно простого решения этой задачи можно воспользоваться созданием разных функций для списка типов в C с использованием подходящего соглашения об именовании сущностей. При таком подходе имена, например, могут выглядеть как hu_flt и hu_dbl . В C будет использоваться макрос:
В C++ будет просто использоваться интерфейс с несколькими конкретизациями шаблона:
И тот и другой подход приведут к появлению одинаково эффективного исполняемого кода. В частности, в скомпилированной программе вызовы hu должны напрямую заменяться вызовами соответствующей C-функции.
Предположим, универсальный интерфейс предоставляет константы времени компиляции. В C это может выглядеть так:
А в C++ можно задействовать похожий механизм, в котором вместо inline используется constexpr :
Макросы
Препроцессоры для C и C++ в наши дни должны выдавать эквивалентные варианты замены макросов соответствующим кодом. Цель тех, кто занимается стандартизацией C и C++, заключается в том, чтобы поддерживать их в полностью согласованном состоянии. Мы уже видели несколько примеров, когда препроцессор при объявлении общих интерфейсов приходит нам на помощь.
В частности, сравнительно недавно препроцессор C++ был оснащён макросами variadic . Это — макросы, которые могут принимать разное количество аргументов.
В заключение давайте рассмотрим более сложный пример вариадического интерфейса с одним и тем же типом для всех параметров. Представим, что у нас есть простая функция, которая принимает массив значений типа double :
Смысл тут в том, что мы хотим дать обоим языкам один и тот же интерфейс, позволяющий принимать фиксированный список значений, создающий массив и передающий его функции.
Приходилось ли вам налаживать взаимодействие между кодом, который написан на C и на C++?