Примеры struct c: Сложные типы данных в Си : структуры, объединения, битовые поля

Содержание

Linux, DevOps и системное администрирование










DevOops

Operating systems

main()

Scripting/coding

Самое читаемое

Архив месяца

Май 2021
ПнВтСрЧтПтСбВс
 12
3456789
10111213141516
17181920212223
24252627282930
31 

« Апр
 
 

Архивы по годам

Архивы по годам
Выберите месяц Апрель 2021  (11) Март 2021  (8) Февраль 2021  (6) Январь 2021  (1) Декабрь 2020  (1) Ноябрь 2020  (9) Октябрь 2020  (9) Сентябрь 2020  (4) Август 2020  (8) Июль 2020  (4) Июнь 2020  (3) Май 2020  (5) Апрель 2020  (9) Март 2020  (8) Февраль 2020  (9) Январь 2020  (2) Декабрь 2019  (9) Ноябрь 2019  (9) Октябрь 2019  (11) Сентябрь 2019  (11) Август 2019  (10) Июль 2019  (2) Июнь 2019  (4) Май 2019  (9) Апрель 2019  (13) Март 2019  (32) Февраль 2019  (20) Январь 2019  (10) Декабрь 2018  (9) Ноябрь 2018  (12) Октябрь 2018  (15) Сентябрь 2018  (12) Август 2018  (14) Июль 2018  (17) Июнь 2018  (18) Май 2018  (21) Апрель 2018  (6) Март 2018  (18) Февраль 2018  (7) Январь 2018  (13) Декабрь 2017  (14) Ноябрь 2017  (6) Октябрь 2017  (24) Сентябрь 2017  (13) Август 2017  (15) Июль 2017  (11) Июнь 2017  (11) Май 2017  (11) Апрель 2017  (7) Март 2017  (18) Февраль 2017  (13) Январь 2017  (14) Декабрь 2016  (12) Ноябрь 2016  (15) Октябрь 2016  (13) Сентябрь 2016  (21) Август 2016  (19) Июль 2016  (14) Июнь 2016  (8) Май 2016  (24) Апрель 2016  (15) Март 2016  (19) Февраль 2016  (21) Январь 2016  (19) Декабрь 2015  (17) Ноябрь 2015  (17) Октябрь 2015  (14) Сентябрь 2015  (13) Август 2015  (1) Июль 2015  (20) Июнь 2015  (23) Май 2015  (26) Апрель 2015  (28) Март 2015  (30) Февраль 2015  (26) Январь 2015  (24) Декабрь 2014  (31) Ноябрь 2014  (21) Октябрь 2014  (28) Сентябрь 2014  (23) Август 2014  (31) Июль 2014  (23) Июнь 2014  (11) Май 2014  (14) Апрель 2014  (8) Март 2014  (11) Февраль 2014  (11) Январь 2014  (11) Декабрь 2013  (12) Ноябрь 2013  (23) Октябрь 2013  (20) Сентябрь 2013  (30) Август 2013  (20) Июль 2013  (6) Июнь 2013  (9) Май 2013  (5) Апрель 2013  (13) Март 2013  (22) Февраль 2013  (36) Январь 2013  (10) Декабрь 2012  (4) Ноябрь 2012  (8) Октябрь 2012  (13) Сентябрь 2012  (29) Август 2012  (24) Июль 2012  (18) Июнь 2012  (2) Май 2012  (4) Март 2012  (5) Февраль 2012  (5) Январь 2012  (25) Декабрь 2011  (15) Ноябрь 2011  (6) Август 2011  (13)

Linux, DevOps и системное администрирование










DevOops

Operating systems

main()

Scripting/coding

Самое читаемое

Архив месяца

Май 2021
ПнВтСрЧтПтСбВс
 12
3456789
10111213141516
17181920212223
24252627282930
31 

« Апр
 
 

Архивы по годам

Архивы по годам
Выберите месяц Апрель 2021  (11) Март 2021  (8) Февраль 2021  (6) Январь 2021  (1) Декабрь 2020  (1) Ноябрь 2020  (9) Октябрь 2020  (9) Сентябрь 2020  (4) Август 2020  (8) Июль 2020  (4) Июнь 2020  (3) Май 2020  (5) Апрель 2020  (9) Март 2020  (8) Февраль 2020  (9) Январь 2020  (2) Декабрь 2019  (9) Ноябрь 2019  (9) Октябрь 2019  (11) Сентябрь 2019  (11) Август 2019  (10) Июль 2019  (2) Июнь 2019  (4) Май 2019  (9) Апрель 2019  (13) Март 2019  (32) Февраль 2019  (20) Январь 2019  (10) Декабрь 2018  (9) Ноябрь 2018  (12) Октябрь 2018  (15) Сентябрь 2018  (12) Август 2018  (14) Июль 2018  (17) Июнь 2018  (18) Май 2018  (21) Апрель 2018  (6) Март 2018  (18) Февраль 2018  (7) Январь 2018  (13) Декабрь 2017  (14) Ноябрь 2017  (6) Октябрь 2017  (24) Сентябрь 2017  (13) Август 2017  (15) Июль 2017  (11) Июнь 2017  (11) Май 2017  (11) Апрель 2017  (7) Март 2017  (18) Февраль 2017  (13) Январь 2017  (14) Декабрь 2016  (12) Ноябрь 2016  (15) Октябрь 2016  (13) Сентябрь 2016  (21) Август 2016  (19) Июль 2016  (14) Июнь 2016  (8) Май 2016  (24) Апрель 2016  (15) Март 2016  (19) Февраль 2016  (21) Январь 2016  (19) Декабрь 2015  (17) Ноябрь 2015  (17) Октябрь 2015  (14) Сентябрь 2015  (13) Август 2015  (1) Июль 2015  (20) Июнь 2015  (23) Май 2015  (26) Апрель 2015  (28) Март 2015  (30) Февраль 2015  (26) Январь 2015  (24) Декабрь 2014  (31) Ноябрь 2014  (21) Октябрь 2014  (28) Сентябрь 2014  (23) Август 2014  (31) Июль 2014  (23) Июнь 2014  (11) Май 2014  (14) Апрель 2014  (8) Март 2014  (11) Февраль 2014  (11) Январь 2014  (11) Декабрь 2013  (12) Ноябрь 2013  (23) Октябрь 2013  (20) Сентябрь 2013  (30) Август 2013  (20) Июль 2013  (6) Июнь 2013  (9) Май 2013  (5) Апрель 2013  (13) Март 2013  (22) Февраль 2013  (36) Январь 2013  (10) Декабрь 2012  (4) Ноябрь 2012  (8) Октябрь 2012  (13) Сентябрь 2012  (29) Август 2012  (24) Июль 2012  (18) Июнь 2012  (2) Май 2012  (4) Март 2012  (5) Февраль 2012  (5) Январь 2012  (25) Декабрь 2011  (15) Ноябрь 2011  (6) Август 2011  (13)

Linux, DevOps и системное администрирование










DevOops

Operating systems

main()

Scripting/coding

Самое читаемое

Архив месяца

Май 2021
ПнВтСрЧтПтСбВс
 12
3456789
10111213141516
17181920212223
24252627282930
31 

« Апр
 
 

Архивы по годам

Архивы по годам
Выберите месяц Апрель 2021  (11) Март 2021  (8) Февраль 2021  (6) Январь 2021  (1) Декабрь 2020  (1) Ноябрь 2020  (9) Октябрь 2020  (9) Сентябрь 2020  (4) Август 2020  (8) Июль 2020  (4) Июнь 2020  (3) Май 2020  (5) Апрель 2020  (9) Март 2020  (8) Февраль 2020  (9) Январь 2020  (2) Декабрь 2019  (9) Ноябрь 2019  (9) Октябрь 2019  (11) Сентябрь 2019  (11) Август 2019  (10) Июль 2019  (2) Июнь 2019  (4) Май 2019  (9) Апрель 2019  (13) Март 2019  (32) Февраль 2019  (20) Январь 2019  (10) Декабрь 2018  (9) Ноябрь 2018  (12) Октябрь 2018  (15) Сентябрь 2018  (12) Август 2018  (14) Июль 2018  (17) Июнь 2018  (18) Май 2018  (21) Апрель 2018  (6) Март 2018  (18) Февраль 2018  (7) Январь 2018  (13) Декабрь 2017  (14) Ноябрь 2017  (6) Октябрь 2017  (24) Сентябрь 2017  (13) Август 2017  (15) Июль 2017  (11) Июнь 2017  (11) Май 2017  (11) Апрель 2017  (7) Март 2017  (18) Февраль 2017  (13) Январь 2017  (14) Декабрь 2016  (12) Ноябрь 2016  (15) Октябрь 2016  (13) Сентябрь 2016  (21) Август 2016  (19) Июль 2016  (14) Июнь 2016  (8) Май 2016  (24) Апрель 2016  (15) Март 2016  (19) Февраль 2016  (21) Январь 2016  (19) Декабрь 2015  (17) Ноябрь 2015  (17) Октябрь 2015  (14) Сентябрь 2015  (13) Август 2015  (1) Июль 2015  (20) Июнь 2015  (23) Май 2015  (26) Апрель 2015  (28) Март 2015  (30) Февраль 2015  (26) Январь 2015  (24) Декабрь 2014  (31) Ноябрь 2014  (21) Октябрь 2014  (28) Сентябрь 2014  (23) Август 2014  (31) Июль 2014  (23) Июнь 2014  (11) Май 2014  (14) Апрель 2014  (8) Март 2014  (11) Февраль 2014  (11) Январь 2014  (11) Декабрь 2013  (12) Ноябрь 2013  (23) Октябрь 2013  (20) Сентябрь 2013  (30) Август 2013  (20) Июль 2013  (6) Июнь 2013  (9) Май 2013  (5) Апрель 2013  (13) Март 2013  (22) Февраль 2013  (36) Январь 2013  (10) Декабрь 2012  (4) Ноябрь 2012  (8) Октябрь 2012  (13) Сентябрь 2012  (29) Август 2012  (24) Июль 2012  (18) Июнь 2012  (2) Май 2012  (4) Март 2012  (5) Февраль 2012  (5) Январь 2012  (25) Декабрь 2011  (15) Ноябрь 2011  (6) Август 2011  (13)

Объявления структур | Microsoft Docs



  • Чтение занимает 4 мин

В этой статье

«Объявление структуры» именует тип и задает последовательность переменных значений («элементы» или «поля» структуры), которые могут иметь разные типы.A «structure declaration» names a type and specifies a sequence of variable values (called «members» or «fields» of the structure) that can have different types. Необязательный идентификатор — тег — предоставляет имя типа структуры и может использоваться в последующих ссылках на тип структуры.An optional identifier, called a «tag,» gives the name of the structure type and can be used in subsequent references to the structure type. Переменная этого типа структуры включает определенную этим типом последовательность целиком.A variable of that structure type holds the entire sequence defined by that type. Структуры в языке C аналогичны типам, известным в других языках как «записи».Structures in C are similar to the types known as «records» in other languages.

СинтаксисSyntax

спецификатор-структуры-или-объединения:struct-or-union-specifier:
    struct-or-union identifieropt{ struct-declaration-list }    struct-or-union identifieropt{ struct-declaration-list }
    struct-or-union identifier    struct-or-union identifier

структура-или-объединение:struct-or-union:
     struct    struct
    union    union

список-объявлений-структуры:struct-declaration-list:
    struct-declaration    struct-declaration
    struct-declaration-list struct-declaration    struct-declaration-list struct-declaration

объявление-структуры:struct-declaration:
    specifier-qualifier-list struct-declarator-list ;    specifier-qualifier-list struct-declarator-list ;

список-спецификаторов-и-квалификаторов:specifier-qualifier-list:
    type-specifier specifier-qualifier-listopt    type-specifier specifier-qualifier-listopt
    type-qualifier specifier-qualifier-listopt    type-qualifier specifier-qualifier-listopt

список-деклараторов-структуры:struct-declarator-list:
    struct-declarator struct-declarator-list , struct-declarator    struct-declarator struct-declarator-list , struct-declarator

декларатор-структуры:struct-declarator:
    declarator    declarator
    type-specifier declaratoropt: constant-expression    type-specifier declaratoropt: constant-expression

Объявление типа структуры не оставляет места для структуры.The declaration of a structure type does not set aside space for a structure. Это всего лишь шаблон для последующих объявлений структурных переменных.It is only a template for later declarations of structure variables.

Ранее определенный идентификатор (тег) можно использовать для ссылки на структурный тип, определенный в другом месте.A previously defined identifier (tag) can be used to refer to a structure type defined elsewhere. В этом случае список-объявлений-структур невозможно повторить, пока определение видно.In this case, struct-declaration-list cannot be repeated as long as the definition is visible. Объявления указателей на структуры и объекты typedef для типов структуры могут использовать тег структуры до определения типа структуры.Declarations of pointers to structures and typedefs for structure types can use the structure tag before the structure type is defined. Однако определение структуры необходимо получить до выполнения каких-либо фактических действий с размером полей.However, the structure definition must be encountered prior to any actual use of the size of the fields. Это неполное определение типа и тега типов.This is an incomplete definition of the type and the type tag. Для того чтобы это определение стало полным, определение типа должно отображаться позже в той же области.For this definition to be completed, a type definition must appear later in the same scope.

Список-объявлений-структуры задает типы и имена элементов структуры.The struct-declaration-list specifies the types and names of the structure members. Аргумент список-объявлений-структуры содержит одну или несколько переменных или объявлений битовых полей.A struct-declaration-list argument contains one or more variable or bit-field declarations.

Каждая переменная, объявленная в списке-объявлений-структуры, определяется как элемент структурного типа.Each variable declared in struct-declaration-list is defined as a member of the structure type. Объявления переменных в списке-объявлений-структуры имеет ту же форму, что и другие объявления переменных, которые обсуждаются в этом разделе, с той разницей, что эти объявления не могут содержать описатели или инициализаторы класса хранения.Variable declarations within struct-declaration-list have the same form as other variable declarations discussed in this section, except that the declarations cannot contain storage-class specifiers or initializers. Элементы структуры могут содержать любые типы переменной, кроме типа void , неполного типа или типа функции.The structure members can have any variable types except type void, an incomplete type, or a function type.

Невозможно объявить элемент так, чтобы он имел тип структуры, в которой отображается.A member cannot be declared to have the type of the structure in which it appears. Однако элемент можно объявить как указатель на структурный тип, в котором он отображается, при условии, что этот структурный тип имеет тег.However, a member can be declared as a pointer to the structure type in which it appears as long as the structure type has a tag. Это позволяет создавать связанные списки структур.This allows you to create linked lists of structures.

Структуры имеют ту же область видимости, что и другие идентификаторы.Structures follow the same scoping as other identifiers. Идентификаторы структур должны отличаться от всех тегов структур, объединений и перечислений с той же областью видимости.Structure identifiers must be distinct from other structure, union, and enumeration tags with the same visibility.

Каждое объявление-структуры в списке-объявления-структуры должно быть уникальным в пределах списка.Each struct-declaration in a struct-declaration-list must be unique within the list. Однако имена идентификаторов в списке-объявления-структуры не должны отличаться от стандартных имен переменных или идентификаторов в других списках объявления структуры.However, identifier names in a struct-declaration-list do not have to be distinct from ordinary variable names or from identifiers in other structure declaration lists.

Доступ к вложенным структурам можно осуществлять так же, как если бы они были объявлены на уровне области файлов.Nested structures can also be accessed as though they were declared at the file-scope level. Например, с данным объявлениемFor example, given this declaration:

struct a
{
    int x;
    struct b
    {
      int y;
    } var2;
} var1;

оба объявления являются допустимыми:these declarations are both legal:

struct a var3;
struct b var4;

ПримерыExamples

В следующих примерах показаны объявления структуры.These examples illustrate structure declarations:

struct employee   /* Defines a structure variable named temp */
{
    char name[20];
    int id;
    long class;
} temp;

Структура employee содержит три члена: name, id и class.The employee structure has three members: name, id, and class. Член name — это 20-элементный массив, а id и class — простые элементы с типом int и long соответственно.The name member is a 20-element array, and id and class are simple members with int and long type, respectively. Идентификатор employee является идентификатором структуры.The identifier employee is the structure identifier.

struct employee student, faculty, staff;

В этом примере определяются три переменных структуры: student, faculty и staff.This example defines three structure variables: student, faculty, and staff. Каждая структура имеет такой же список из трех элементов.Each structure has the same list of three members. Эти элементы объявлены как имеющие структурный тип employee, определенный в предыдущем примере.The members are declared to have the structure type employee, defined in the previous example.

struct           /* Defines an anonymous struct and a */
{                /* structure variable named complex  */
    float x, y;
} complex;

Структура complex содержит два элемента с типом float  — x и y.The complex structure has two members with float type, x and y. Тип структуры не имеет тегов и, следовательно, является безымянным или анонимным.The structure type has no tag and is therefore unnamed or anonymous.

struct sample   /* Defines a structure named x */
{
    char c;
    float *pf;
    struct sample *next;
} x;

Первые два элемента структуры — это переменная char и указатель на значение float .The first two members of the structure are a char variable and a pointer to a float value. Третий элемент, next, объявляется как указатель на определяемый структурный тип (sample).The third member, next, is declared as a pointer to the structure type being defined (sample).

Анонимные структуры могут быть полезны, если именованный тег не требуется.Anonymous structures can be useful when the tag named is not needed. Это происходит в том случае, если одно объявление определяет все экземпляры структуры.This is the case when one declaration defines all structure instances. Пример:For example:

struct
{
    int x;
    int y;
} mystruct;

Встроенные структуры часто являются анонимными.Embedded structures are often anonymous.

struct somestruct
{
    struct    /* Anonymous structure */
    {
        int x, y;
    } point;
    int type;
} w;

Блок, относящийся только к системам MicrosoftMicrosoft Specific

Компилятор позволяет использовать безразмерный массив или массив нулевого размера в качестве последнего члена структуры.The compiler allows an unsized or zero-sized array as the last member of a structure. Это полезно, если размер константного массива различается при использовании в разных ситуациях.This can be useful if the size of a constant array differs when used in various situations. Объявление такой структуры выглядит следующим образом.The declaration of such a structure looks like this:

struct identifier { set-of-declarations type array-name []; };struct identifier { set-of-declarations type array-name[]; };

Безразмерные массивы могут отображаться только в качестве последнего члена структуры.Unsized arrays can appear only as the last member of a structure. Структуры, содержащие объявления безразмерных массивов, могут вкладываться в другие структуры при условии, что никакие другие элементы не объявлены ни в одной из внешних структур.Structures containing unsized array declarations can be nested within other structures as long as no further members are declared in any enclosing structures. Массивы таких структур использовать не разрешается.Arrays of such structures are not allowed. Оператор sizeof , если он применен к переменной этого типа или к самому типу, предполагает, что размер массива равен 0.The sizeof operator, when applied to a variable of this type or to the type itself, assumes 0 for the size of the array.

Объявления структуры также можно задать без декларатора, если они являются элементами другой структуры или объединения.Structure declarations can also be specified without a declarator when they are members of another structure or union. Уровень имен полей повышается до уровня внешней структуры.The field names are promoted into the enclosing structure. Например, безыменная структура выглядит следующим образом:For example, a nameless structure looks like this:

struct s
{
    float y;
    struct
    {
        int a, b, c;
    };
    char str[10];
} *p_s;
.
.
.
p_s->b = 100;  /* A reference to a field in the s structure */

См. справочные сведения о структурах в разделе Элементы структур и объединений.See Structure and Union Members for information about structure references.

Завершение блока, относящегося только к системам МайкрософтEND Microsoft Specific

См. такжеSee also

Деклараторы и объявления переменныхDeclarators and Variable Declarations



Понимание языка C для встраиваемых систем: Что такое структуры?

Добавлено 7 июня 2019 в 23:03

Сохранить или поделиться

Данная статья предоставляет основную информацию о структурах в программировании для встраиваемых систем на языке C.

После введения в структуры мы рассмотрим некоторые важные применения этого мощного объекта данных. Затем мы рассмотрим синтаксис языка C, позволяющий объявлять структуры. Наконец, мы кратко обсудим требование по выравниванию данных. Мы увидим, что мы можем уменьшить размер структуры, просто изменив порядок ее членов.

Структуры

Ряд переменных одного типа, которые логически связаны друг с другом, может быть сгруппирован в виде массива. Работа с группой, а не с набором независимых переменных, позволяет нам упорядочивать данные и использовать их более удобным способом. Например, мы можем определить следующий массив для хранения последних 50 отсчетов АЦП, который оцифровывает голосовой ввод:

uint16_t voice[50];

Обратите внимание, что uint16_t – это целочисленный тип без знака с шириной ровно 16 бит. Он определен в стандартной библиотеке C stdint.h, которая предоставляет типы данных определенной длины в битах, не зависящие от спецификаций системы.

Массивы могут быть использованы для группирования нескольких переменных одного типа данных. Но что если есть связь между переменными разных типов данных? Можем ли мы рассматривать эти переменные в нашей программе как группу? Например, предположим, что нам нужно указать частоту дискретизации АЦП, который генерирует голосовой массив, объявленный выше. Мы можем определить переменную типа float для хранения значения частоты дискретизации:

float sample_rate;

Хотя переменные voice и sample_rate связаны друг с другом, они определены как две независимые переменные. Чтобы связать эти две переменные друг с другом, мы можем использовать мощную конструкцию данных языка C, которая называется структурой. Структуры позволяют нам группировать различные типы данных и работать с ними как с одним объектом данных. Структура может включать в себя различные виды типов переменных, такие как другие структуры, указатели на функции, указатели на структуры и так далее. Для примера с голосом мы можем использовать следующую структуру:

struct record {
  uint16_t voice[50];
  float sample_rate;
};

В этом случае у нас есть структура с именем record, которая имеет два члена или поля: первый член – это массив элементов uint16_t, а второй – переменная типа float. Синтаксис начинается с ключевого слова struct. Слово после ключевого слова struct является необязательным именем, используемым позже для ссылки на структуру. Другие детали определения и использования структур мы обсудим в оставшейся части статьи.

Почему структуры важны?

Приведенный выше пример указывает на важное применение структур, то есть определение зависящих от приложения объектов данных, которые могут связывать друг с другом отдельные переменные разных типов. Это не только приводит к эффективному способу манипулирования данными, но также позволяет нам реализовывать специализированные структуры, называемые структурами данных.

Структуры данных могут использоваться для различных применений, таких как обмен сообщениями между двумя встроенными системами и хранение данных, собранных с датчика, в несмежных ячейках памяти.

Рисунок 1 – Структуры могут использоваться для реализации связного списка

Кроме того, структуры являются полезными объектами данных, когда программе требуется доступ к регистрам периферийного устройства микроконтроллера с отображаемой памятью.

Рисунок 2 – Распределение памяти микроконтроллера STM32

Объявление структуры

Чтобы использовать структуры, нам сначала нужно задать шаблон структуры. Рассмотрим пример кода, приведенный ниже:

struct record {
 uint16_t voice[4];
 float sample_rate;
};

Он указывает макет или шаблон для создания будущих переменных этого типа. Этот шаблон включает в себя массив uint16_t и переменную типа float. Имя шаблона – record, оно идет после ключевого слова struct. Стоит отметить, что для хранения шаблона структуры память не выделяется. Выделение памяти происходит только определения переменной структуры на основе этого шаблона. Следующий код объявляет переменную mic1 приведенного выше шаблона:

struct record mic1;

Теперь для переменной mic1 выделен раздел памяти. В нем есть место для хранения четырех элементов uint16_t массива и одной переменной float.

Доступ к членам структуры можно получить с помощью оператора члена (.). Например, следующий код присваивает значение 100 первому элементу массива и копирует значение sample_rate в переменную fs (которая должна быть типа float).

mic1.voice[0]=100;
fs=mic1.sample_rate;

Другие способы объявления структуры

В предыдущем разделе мы рассмотрели один из способов объявления структур. Язык C поддерживает и другие форматы, которые будут рассмотрены в этом разделе. Вы, вероятно, во всех своих программах будете придерживаться одного формата, но иногда знакомство с остальными может быть полезным.

Общий синтаксис объявления шаблона структуры:

struct tag_name {
  type_1    member_1;
  type_2    member_2;
  …
  type_n    member_n;

} variable_name;

tag_name и variable_name являются необязательными идентификаторами. Обычно мы видим хотя бы один из этих двух идентификаторов, но есть случаи, когда мы можем убрать их обоих.

Синтаксис 1. Когда присутствуют tag_name и variable_name, мы определяем переменную структуры сразу после шаблона. Используя этот синтаксис, мы можем переписать предыдущий пример следующим образом:

struct record {
  uint16_t  voice[4];
  float     sample_rate;
} mic1;

Теперь, если нам нужно определить другую переменную (mic2), мы можем написать:

struct record mic2;

Синтаксис 2. Включено только variable_name. Используя этот синтаксис, мы можем переписать пример из предыдущего раздела следующим образом:

struct {
  uint16_t  voice[4];
  float     sample_rate;
} mic1;

В этом случае мы должны определить все свои переменные сразу после шаблона, и определить другие переменные позже в нашей программе мы не сможем (потому что шаблон не имеет имени, и далее мы не сможем ссылаться на него).

Синтаксис 3. В этом случае нет ни tag_name, ни variable_name. Шаблоны структур, определенные таким образом, называются анонимными структурами. Анонимная структура может быть определена в другой структуре или объединении. Пример приведен ниже:

struct test {
  // анонимная структура 
  struct { 
    float f;
    char a; 
  };
} test_var;

Чтобы получить доступ к членам показанной выше анонимной структуры, мы можем использовать оператор члена (.). Следующий код присваивает значение 1.2 члену f.

test_var.f=1.2;

Поскольку структура является анонимной, мы получаем доступ к ее членам, используя оператор члена только один раз. Если бы она имела имя, как в следующем примере, нам пришлось бы использовать оператор члена дважды:

struct test {
  struct { 
    float f;
    char a; 
  } nested;
} test_var;

В этом случае мы должны использовать следующий код, чтобы присвоить значение 1.2 для f:

test_var.nested.f=1.2;

Как видите, анонимные структуры могут сделать код более читабельным и менее многословным. Также можно вместе со структурой использовать ключевое слово typedef, чтобы определить новый тип данных. Этот метод мы рассмотрим в следующей статье.

Распределение памяти для структуры

Стандарт C гарантирует, что члены структуры будут располагаться в памяти один за другим в порядке, в котором они объявлены в структуре. Адрес памяти первого члена будет таким же, как адрес самой структуры. Рассмотрим следующий пример:

struct Test2{
  uint8_t   c;
  uint32_t  d;
  uint8_t   e;
  uint16_t  f;
} MyStruct;

Для хранения переменных c, d, e и f будут выделены четыре области памяти. Порядок расположения в памяти будет соответствовать порядку объявления членов: область для c будет иметь наименьший адрес, затем идут d, e и, наконец, f. Сколько байт нам нужно для хранения этой структуры? Учитывая размер переменных, мы знаем, что, по крайней мере, 1+4+1+2=8 байт требуется хранения этой структуры. Однако, если мы скомпилируем этот код для 32-разрядной машины, мы неожиданно заметим, что размер MyStruct составляет 12 байтов, а не 8! Это связано с тем, что компилятор имеет определенные ограничения при выделении памяти для разных элементов структуры. Например, 32-разрядное целое число может храниться только в областях памяти, адрес которых делится на четыре. Такие ограничения, называемые требованиями выравнивания данных, реализованы для более эффективного доступа процессора к переменным. Выравнивание данных приводит к некоторой потере места (или заполнению) в распределении памяти. Здесь дается только краткое представление этой темы; подробности мы рассмотрим в следующей статье серии.

Рисунок 3 – Выравнивание данных приводит к некоторой потере места (или заполнению) в распределении памяти

Зная о требованиях к выравниванию данных, мы можем изменить в структуре порядок членов и повысить эффективность использования памяти. Например, если мы перепишем приведенную выше структуру, как показано ниже, ее размер на 32-разрядной машине уменьшится до 8 байт.

struct Test2{
  uint32_t  d;
  uint16_t  f;
  uint8_t   c;  
  uint8_t   e;
} MyStruct;

Для встраиваемой системы с ограниченным объемом памяти это уменьшение размера объекта данных с 12 до 8 байт является существенной экономией, особенно когда программе требуется много таких объектов данных.

В следующей статье мы обсудим выравнивание данных более подробно и рассмотрим некоторые примеры использования структур во встраиваемых системах.

Подведем итоги

  • Структуры позволяют нам определять зависящие от приложения объекты данных, которые могут связывать друг с другом отдельные переменные разных типов. Это приводит к эффективным средствам манипулирования данными.
  • Специализированные структуры, называемые структурами данных, могут использоваться для различных применений, таких как обмен сообщениями между двумя встроенными системами и хранение данных, собранных с датчика, в несмежных областях памяти.
  • Структуры полезны, когда нам необходим доступ к регистрам периферийного устройства микроконтроллера с отображаемой памятью.
  • Возможно, мы можем повысить эффективность использования памяти, изменив порядок членов в структуре.

Оригинал статьи:

Теги

Embedded CSTM32Язык C для встраиваемых систем

Сохранить или поделиться

Структуры в C ++ | Портал информатики для гиков

Мы часто сталкиваемся с ситуациями, когда нам нужно хранить группу данных, будь то схожих типов или не схожих типов данных. Мы видели массивы в C ++, которые используются для хранения набора данных схожих типов данных в смежных местах памяти.

В отличие от массивов, структуры в C ++ являются определяемыми пользователем типами данных, которые используются для хранения группы элементов не похожих типов.

Что такое структура?

Структура — это определяемый пользователем тип данных в C / C ++. Структура создает тип данных, который можно использовать для группировки элементов, возможно, разных типов в один тип.

Структуры в C ++

Как создать структуру?

Ключевое слово struct используется для создания структуры. Общий синтаксис для создания структуры, как показано ниже:

struct structureName{
    member1;
    member2;
    member3;
    .
    .
    .
    memberN;
};

Структуры в C ++ могут содержать два типа членов:

  • Элемент данных : эти члены являются обычными переменными C ++. Мы можем создать структуру с переменными разных типов данных в C ++.
  • Функции- члены: Эти члены являются обычными функциями C ++. Наряду с переменными, мы также можем включить функции в объявление структуры.

Пример :

int roll;

int age;

int marks;

      

void printDetails()

{

    cout<<"Roll = "<<roll<<"\n";

    cout<<"Age = "<<age<<"\n";

    cout<<"Marks = "<<marks;

}

В приведенной выше структуре элементы данных представляют собой три целочисленные переменные для хранения номера броска, возраста и отметок любого учащегося, а функция-член — это printDetails (), которая печатает все вышеуказанные сведения о любом учащемся .

Как объявить структурные переменные?

Переменная структуры может быть объявлена с помощью объявления структуры или в виде отдельного объявления, такого как базовые типы.

struct Point

{

   int x, y;

} p1; 

  

  

struct Point

{

   int x, y;

}; 

  

int main()

{

   struct Point p1; 

}

Примечание: в C ++ ключевое слово struct является необязательным перед объявлением переменной. В Си это обязательно.

Как инициализировать элементы структуры?
Члены структуры не могут быть инициализированы с декларацией. Например, следующая программа на С не скомпилирована.
Но считается правильным в C ++ 11 и выше.

struct Point

{

   int x = 0; 

   int y = 0; 

}; 

Причина вышеуказанной ошибки проста: когда объявляется тип данных, для него не выделяется память. Память выделяется только при создании переменных.

Элементы структуры могут быть инициализированы с помощью фигурных скобок ‘{}’. Например, следующее является действительной инициализацией.

struct Point

{

   int x, y;

}; 

  

int main()

{

   

   

   struct Point p1 = {0, 1}; 

}

Как получить доступ к элементам структуры?
Доступ к членам структуры осуществляется с помощью оператора точка (.).

#include <iostream>

using namespace std;

  

struct Point {

    int x, y;

};

  

int main()

{

    struct Point p1 = { 0, 1 };

  

    

    p1.x = 20;

    cout << "x = " << p1.x << ", y = " << p1.y;

  

    return 0;

}

Выход:

x = 20, y = 1

Что такое массив структур?

Как и другие примитивные типы данных, мы можем создать массив структур.

#include <iostream>

using namespace std;

  

struct Point {

    int x, y;

};

  

int main()

{

    

    struct Point arr[10];

  

    

    arr[0].x = 10;

    arr[0].y = 20;

  

    cout << arr[0].x << " " << arr[0].y;

    return 0;

}

Выход:

10 20

Что такое структурный указатель?
Как и примитивные типы, мы можем иметь указатель на структуру. Если у нас есть указатель на структуру, доступ к членам осуществляется с помощью оператора стрелки (->) вместо оператора точки (.).

#include <iostream>

using namespace std;

  

struct Point {

    int x, y;

};

  

int main()

{

    struct Point p1 = { 1, 2 };

  

    

    struct Point* p2 = &p1;

  

    

    

    cout << p2->x << " " << p2->y;

    return 0;

}

Выход:

1 2

Что такое выравнивание элементов конструкции?
Смотрите http://espressocode.top/structure-member-alignment-padding-and-data-packing/

В C ++ структура такая же, как у класса, за исключением нескольких различий. Самым важным из них является безопасность. Структура не защищена и не может скрыть детали своей реализации от конечного пользователя, пока класс защищен и может скрыть детали программирования и проектирования. Узнайте больше о различиях между структурами и классами в C ++ .

Рекомендуемые посты:

Структуры в C ++

0.00 (0%) 0 votes

typedef — КРАТКИЙ ОБЗОР. Язык Си

typedef — КРАТКИЙ ОБЗОР

     Функция typedef позволяет нам создать свое собственное имя типа. Это напоминает директиву #define, но со следующими тремя изменениями:

1. В отличие от #define функция typedef дает символические имена, но ограничивается только типами данных.

2. Функция typedef выполняется компилятором, а не препроцессором.

3. В своих пределах функция typedef более гибка, чем #define.

     Посмотрим, как она работает. Предположим, вы хотите использовать термин real для чисел типа float. Тогда вы определяете термин real, как если бы он был переменной типа float, и перед его определением ставите ключевое слово typedef:

typedef float real;

С этого момента вы можете использовать real для определения переменных:

real х, у[25], *рr;

Область действия такого определения зависит от расположения оператора typedef. Если определение находится внутри функции, то область действия локальна и ограничена этой функцией. Если определение расположено вне функции, то область действия глобальна.

Часто в этих определениях используются прописные буквы, чтобы напомнить пользователю, что имя типа является на самом деле символической аббревиатурой:


typedef float REAL;

В последнем примере можно было бы применить директиву #define. А здесь это делать нельзя:

typedef char *STRING;

Без ключевого слова typedef оператор определял бы STRING как указатель на тип char. С ключевым словом оператор делает STRING идентификатором указателей на тип char. Так,

STRING name, sign;

означает

char *name, *sign;

Мы можем использовать typedef и для структур. Вот пример:

typedef struct COMPLEX {

float real;

float imag; };

Кроме того, можно использовать тип COMPLEX для представления комплексных чисел.

     Одна из причин использования typedef заключается в создании удобных, распознаваемых имен для часто встречающихся типов. Например, многие пользователи предпочитают применять STRING или его эквивалент, как это мы делали выше. Вторая причина: имена typedef часто используются для сложных типов. Например, описание

typedef char *FRPTC ( ) [5];

приводит к тому, что FRPTC объявляет тип, являющийся функцией, которая возвращает указатель на пятиэлементный массив типа char. (См. «Причудливые описания».)

Третья причина использования typedef заключается в том, чтобы сделать программы более мобильными. Предположим, например, что вашей программе нужно использовать 16-разрядные числа. В некоторых системах это был бы тип short, в других же он может быть типом int. Если вы использовали в ваших описаниях short или int, то должны изменить все описания, когда перейдете от одной системы к другой. Вместо этого сделайте следующее, В файле директивы #include есть такое определение:

typedef short TWOBYTE;

Используйте TWOBYTE в ваших программах для переменных типа short, которые должны быть 16-разрядными. Тогда если вы перемешаете программу туда, где необходимо использовать тип int, то следует только изменить одно определение в вашем файле директивы #include:

typedef int TWOBYTE;

Это пример того, что делает язык Си столь мобильным. При использовании typedеf следует иметь в виду, что он не создаст новых типов, он только создает удобные метки. 












Почему мы должны так часто вводить структуру в C?

Оказывается, есть плюсы и минусы. Полезным источником информации является основополагающая книга «Экспертное программирование на языке Си» (глава 3). Вкратце, в C у вас есть несколько пространств имен: теги , типы, имена членов и идентификаторы . typedef вводит псевдоним для типа и находит его в пространстве имен тегов. А именно

  typedef struct Tag {
... участники ...
}Тип;
  

определяет две вещи.Один тег в пространстве имен тегов и один тип в пространстве имен типов. Таким образом, вы можете использовать как Type myType , так и struct Tag myTagType . Объявления типа struct Type myType или Tag myTagType недопустимы. Кроме того, в декларации вроде этого:

  typedef Тип * Type_ptr;
  

мы определяем указатель на наш Тип. Итак, если мы объявим:

  Type_ptr var1, var2;
struct Tag * myTagType1, myTagType2;
  

, затем var1 , var2 и myTagType1 — это указатели на Type, а myTagType2 — нет.

В вышеупомянутой книге упоминается, что структуры определения типов не очень полезны, поскольку они только избавляют программиста от написания слова struct. Однако у меня есть возражение, как и у многих других программистов на C. Хотя иногда он превращается в обфускацию некоторых имен (поэтому это не рекомендуется в больших базах кода, таких как ядро), когда вы хотите реализовать полиморфизм в C, это очень помогает найти здесь подробности. Пример:

  typedef struct MyWriter_t {
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
} MyWriter;
  

вы можете сделать:

  недействителен my_writer_func (MyPipe * s)
{
    MyWriter * self = (MyWriter *) s;
    uint32_t myFlags = self-> flags;
...
}
  

Таким образом, вы можете получить доступ к внешнему члену ( флагов ) с помощью внутренней структуры ( MyPipe ) посредством приведения. Для меня приведение всего типа менее запутанно, чем выполнение (struct MyWriter_ *) s; каждый раз, когда вы захотите выполнить такую ​​функцию. В этих случаях очень важно иметь краткие ссылки, особенно если вы активно используете эту технику в своем коде.

Наконец, последний аспект с типами typedef ed — это невозможность их расширения, в отличие от макросов. Если, например, у вас:

  #define X char [10] или
typedef char Y [10]
  

, затем вы можете объявить

  без знака X x; но нет
беззнаковый Y y;
  

На самом деле нас это не волнует для структур, потому что это не применяется к спецификаторам хранилища ( volatile и const ).

Struct — Примеры программирования

C ++ поддерживает второе ключевое слово struct , которое можно использовать для определения типов классов.Ключевое слово struct унаследовано от C.

Разница между структурами и классами
Единственное различие между структурами и классами в C ++ состоит в том, что члены структуры по умолчанию имеют общедоступную видимость, а члены класса по умолчанию имеют частную видимость.

Если мы определяем класс с помощью ключевого слова class, то любые члены, определенные до первой метки доступа, неявно являются закрытыми; если мы используем ключевое слово struct, то эти члены будут общедоступными. Независимо от того, определяем ли мы класс с помощью ключевого слова class или ключевого слова struct, влияет только на начальный уровень доступа по умолчанию.

Мы могли бы определить наш Sales_item эквивалентно, написав

Пример

struct Sales_item
{
     
    
     частный:
         std :: string isbn;
         unsigned units_sold;
         двойная выручка;
 };
 

Есть только два различия между этим определением класса и нашим первоначальным определением класса: здесь мы используем ключевое слово struct и исключаем использование ключевого слова public сразу после открывающей фигурной скобки. Члены структуры являются общедоступными, если не указано иное, поэтому в общедоступной метке нет необходимости.

Подробнее о указателях.

На структуры можно указывать указатели собственного типа.

Пример


#include 
#include <строка>
#include <поток>
используя пространство имен std;
 
struct movies_t
{
  строковое название;
  int год;
};
 
int main ()
{
  строка mystr;
 
  movies_t amovie;
  movies_t * pmovie;
  pmovie = & amovie;
 
  cout << "Введите заголовок:";
  
  getline (cin, pmovie-> title);
  cout << "Введите год:";
  getline (cin, mystr);
  (stringstream) mystr >> pmovie-> год;
 
  cout << "\ nВы ввели: \ n";
  cout << pmovie-> title;
  cout << "(" << pmovie-> год << ") \ n";
 
  возврат 0;
}
 

Пример

struct movies_t
{
  строковое название;
  int год;
};
 
struct friends_t
{
  имя строки;
  строковый адрес электронной почты;
  movies_t favourite_movie;
} Чарли, Мария;
 
friends_t * pfriends = & charlie;
 

Пример

используя std :: cout;
используя std :: cin;
используя std :: endl;
 
struct person_str
{
  имя строки;
  int age;
 
  
  person_str ()
  {
        name = "по умолчанию";
        возраст = 77;
 }
 
  void print ();
};
 
void person_str :: print ()
{
    
    cout << name << "" << this-> age << endl;
}
 
int main ()
{
    person_str p1;
    p1.name = "Chrys";
    p1.age = 26;
 
    p1.print ();
}
 

Пример

#include 
#include <строка>
используя пространство имен std;
 
typedef struct dataElement
{
   строка SVal;
   int iVal;
   bool hasData;
 
   dataElement ()
      : iVal (-1), hasData (0)
   {}
} DataElement;
 
основной()
{
    DataElement * RealData;
    RealData = новый элемент данных [5];
 
    RealData [0] .SVal = "Значение загружено в первый элемент структуры.";
    RealData [0] .hasData = 1;
 
    cout << "Первый элемент 0:" << RealData [0].SVal << endl;
    cout << "" << RealData [0] .hasData << endl;
    cout << "Второй элемент 1:" << RealData [1] .SVal << endl;
    cout << "" << RealData [1] .hasData << endl;
    cout << "" << RealData [1] .iVal << endl;
 
    удалить [] RealData;
}
 

Вы можете довольно легко передавать структуры как параметры функции. Тип параметра совпадает с именем типа структуры.

Пример
Это функция, которая отображает подробную информацию о человеке.

#include 
#include <строка>
 
используя std :: string;
используя std :: cout;
используя std :: cin;
используя std :: endl;
 
структура человека
{имя строки;
    int eye_colour;
    высота поплавка;
};
 
void display_details (человек кто-то);
 
int main ()
{
    представь меня;
 
    me.name = "Chrys";
    me.eye_colour = 2;
    me.height = 1,90;
 
    display_details (я);
 
}
 
void display_details (человек кто-то)
{
    cout << "Имя:" << something_I_know.name << endl;
        cout << "Цвет глаз:";
        переключатель (something_I_know.eye_colour)
        {
        случай 1: cout << "Коричневый"; перерыв;
               случай 2: cout << "Синий"; перерыв;
               случай 3: cout << "Зеленый"; перерыв;
               по умолчанию: cout << "Неизвестно";
         }
 
    cout << endl;
        cout << "Высота:" << something_I_know.height
         << "метры" << endl;
}
 

Пример
Функция, которая связана с такой структурой, называется функцией-членом этой структуры.

прямоугольник структуры
{
  двойная длина, ширина;
  двойная зона ()
 {
    длина возврата * ширина;
 }
 двойной периметр ()
 {
    return 2 * (длина + ширина);
 }
};
 

C ++ позволяет объявлять структуры как шаблоны. Другими словами, составные члены структуры не обязательно принадлежат к определенному типу.

Пример

Следующая структура хранит две переменные пользовательского типа и имеет перегруженный оператор «плюс».

template  struct twothings
{
    Один;
    B два;
    оператор двойного действия + (const twothings & arg) const
    {
       два раза  темп;
       темп.один = один + arg.one;
       temp.two = two + arg.two;
       возвратная температура;
    }
};
 

Язык C - разыменование указателя на структуру

Пример

Допустим, у нас есть следующая структура:

  структура MY_STRUCT
{
    int my_int;
    float my_float;
};
  

Мы можем определить MY_STRUCT , чтобы опустить ключевое слово struct , поэтому нам не нужно вводить struct MY_STRUCT каждый раз, когда мы его используем.Однако это необязательно.

  typedef struct MY_STRUCT MY_STRUCT;
  

Если у нас есть указатель на экземпляр этой структуры

  MY_STRUCT * экземпляр;
  

Если этот оператор появляется в области видимости файла, экземпляр будет инициализирован нулевым указателем при запуске программы. Если этот оператор появляется внутри функции, его значение не определено. Переменная должна быть инициализирована так, чтобы указывать на допустимую переменную MY_STRUCT или на динамически выделяемое пространство, прежде чем ее можно будет разыменовать.Например:

  MY_STRUCT info = {1, 3.141593F};
MY_STRUCT * instance = & info;
  

Когда указатель действителен, мы можем разыменовать его, чтобы получить доступ к его членам, используя одну из двух разных нотаций:

  int a = (* экземпляр) .my_int;
float b = instance-> my_float;
  

Хотя оба этих метода работают, лучше использовать оператор стрелки -> , а не комбинацию скобок, оператора разыменования * и точки ., потому что его легче читать и понимать, особенно при вложенном использовании.

Еще одно важное отличие показано ниже:

  MY_STRUCT copy = * экземпляр;
copy.my_int = 2;
  

В этом случае копия содержит копию содержимого экземпляра . Изменение my_int из копии не изменит его в экземпляре .

  MY_STRUCT * ref = instance;
ref-> my_int = 2;
  

В этом случае ref является ссылкой на экземпляр .Изменение my_int с использованием ссылки изменит его в экземпляре .

Обычно в качестве параметров функций используются указатели на структуры, а не сами структуры. Использование структур в качестве параметров функции может привести к переполнению стека, если структура большая. Использование указателя на структуру использует достаточно места в стеке только для указателя, но может вызвать побочные эффекты, если функция изменяет структуру, которая передается в функцию.

Примеры исходного кода для наших учебных модулей

Компоненты веб-решения Пример из учебного курса Well House Consultants
Подробнее о компонентах веб-решения [ссылка]

Исходный код: примеры.txt Модуль: A100

Эта страница является только примером - вы запустили сценарий «Пример исходного кода
» на веб-сайте Well House Consultants, но
вы не сказали нам, какой пример вам нужен. Перейдите по ссылкам
, чтобы найти конкретный пример
, который вы ищете.

Узнать об этом предмете

Книги по этой теме

Да. В нашей библиотеке более 700 книг. Книги
Прикрывающее развертывание лампы перечислены здесь, и когда вы выбрали
соответствующую книгу мы свяжем вас с Amazon для заказа.

Другие примеры

Этот пример взят из нашего учебного модуля «Компоненты веб-решения». Вы найдете описание темы и некоторые
другие тесно связанные примеры на индексной странице модуля «Компоненты веб-решения».

Полное описание исходного кода

Вы можете узнать больше об этом примере на учебных курсах, перечисленных на этой странице,
на котором вы получите полный набор обучающих заметок.

Многие другие учебные модули доступны для загрузки (для ограниченного использования) с
наш центр загрузки под
Лицензия Open Training Notes.

Другие ресурсы

• В нашем центре решений есть ряд более длинных технических статей.
• В нашем архиве форумов Opentalk есть центр вопросов и ответов.
• Лошадиный рот дает ежедневные подсказки или мысли.
• Дополнительные ресурсы доступны через ресурсный центр.
• Все эти ресурсы можно искать с помощью нашей поисковой системы
• И здесь есть глобальный индекс.

Назначение этого сайта

Это образец программы, демонстрация класса или ответ от
учебный курс.Это основная цель
заключается в предоставлении послекурсовых услуг клиентам, которые посещали наши
общественное частное или
на сайте курсы, но примеры сделаны
обычно доступны при условиях, описанных ниже.

Автор веб-сайта

Этот веб-сайт написан и поддерживается
Консультанты Well House.

Условия использования

Прошедшие участники наших учебных курсов могут использовать индивидуальные
примеры в процессе их программирования, но необходимо проверить
примеры, которые они используют, чтобы убедиться, что они подходят для их
работа. Помните, что некоторые из наших примеров показывают вам, как , а не , делать
вещи - проверяйте в своих заметках.
Well House Consultants не несет ответственности
на предмет соответствия этих примеров программ потребностям клиентов.

Авторские права на эту программу принадлежат Well House Consultants Ltd.
запрещено использовать его для проведения собственных учебных курсов
без нашего предварительного письменного разрешения. Смотрите наши
страницу о предоставлении учебных программ для получения более подробной информации.

Любое из наших изображений в этом коде ЗАПРЕЩАЕТСЯ повторно использовать в общедоступном URL-адресе без нашего
предварительное разрешение.Для добросовестного личного использования мы часто предоставляем вам разрешение.
что вы предоставляете обратную ссылку. За коммерческое использование веб-сайта взимается лицензионный сбор за
каждое использованное изображение - детали по запросу.

8.4 - Конструкции | Изучите C ++

Автор Alex 20 июня 2007 г. | последнее изменение: nascardriver: 20 февраля 2021 г.

В программировании есть много случаев, когда нам нужно более одной переменной для представления объекта. Например, чтобы представить себя, вы можете сохранить свое имя, дату рождения, рост, вес или любое другое количество характеристик о себе.Вы можете сделать это так:

std :: string myName {};

int myBirthYear {};

int myBirthMonth {};

int myBirthDay {};

int myHeightInches {};

int myWeightPounds {};

Однако теперь у вас есть 6 независимых переменных, которые никак не сгруппированы. Если вы хотите передать информацию о себе функции, вам придется передавать каждую переменную отдельно.Кроме того, если вы хотите сохранить информацию о ком-то еще, вам нужно будет объявить еще 6 переменных для каждого дополнительного человека! Как видите, это может быстро выйти из-под контроля.

К счастью, C ++ позволяет нам создавать наши собственные определяемые пользователем агрегированные типы данных. Агрегированный тип данных - это тип данных, который группирует вместе несколько отдельных переменных. Одним из простейших типов агрегированных данных является структура. struct (сокращение от «структура») позволяет нам группировать переменные смешанных типов данных вместе в единое целое.

Объявление и определение структур

Поскольку структуры определяются пользователем, мы сначала должны сообщить компилятору, как выглядит наша структура, прежде чем мы сможем начать ее использовать. Для этого мы объявляем нашу структуру с помощью ключевого слова struct . Вот пример объявления структуры:

struct Employee

{

int id {};

int age {};

двойная заработная плата {};

};

Это сообщает компилятору, что мы определяем структуру с именем Employee.Структура Employee содержит внутри 3 переменных: int с именем id, int с именем age и двойное имя wage. Эти переменные, которые являются частью структуры, называются членами (или полями). Имейте в виду, что Employee - это просто объявление - даже несмотря на то, что мы сообщаем компилятору, что структура будет иметь переменные-члены, в это время память не выделяется. По соглашению имена структур начинаются с заглавной буквы, чтобы отличать их от имен переменных.

Предупреждение. Одна из самых простых ошибок C ++ - это забыть о точке с запятой в конце объявления структуры.Это вызовет ошибку компилятора в следующей строке кода . Современные компиляторы, такие как Visual Studio 2010, укажут вам, что вы, возможно, забыли точку с запятой, но более старые или менее сложные компиляторы могут этого не делать, что может затруднить обнаружение фактической ошибки.

Чтобы использовать структуру Employee, мы просто объявляем переменную типа Employee:

Сотрудник Джо {}; // struct Employee пишется с заглавной буквы, переменная joe не

Это определяет переменную типа Сотрудник с именем joe.Как и в случае с обычными переменными, определение структурной переменной выделяет память для этой переменной.

Можно определить несколько переменных одного и того же типа структуры:

Сотрудник Джо {}; // создаем структуру Employee для Joe

Employee frank {}; // создаем структуру Employee для Фрэнка

Доступ к элементам структуры

Когда мы определяем переменную, такую ​​как Employee joe , joe относится ко всей структуре (которая содержит переменные-члены).Чтобы получить доступ к отдельным элементам, мы используем оператор выбора элементов (который представляет собой точку). Вот пример использования оператора выбора элемента для инициализации каждой переменной-члена:

Сотрудник Джо {}; // создаем структуру Employee для Джо

joe.id = 14; // присваиваем значение идентификатору элемента в struct joe

joe.age = 32; // присваиваем значение возрасту члена в struct joe

joe.заработная плата = 24,15; // присвоить значение заработной плате члена в структуре joe

Employee frank {}; // создаем структуру Employee для Фрэнка

frank.id = 15; // присваиваем значение идентификатору члена в struct frank

frank.age = 28; // присваиваем значение возрасту члена в struct frank

frank.wage = 18.27; // присвоить значение заработной плате члена в структуре frank

Как и обычные переменные, переменные-члены структуры не инициализируются и обычно содержат мусор.Мы должны инициализировать их вручную.

В приведенном выше примере очень легко определить, какие переменные-члены принадлежат Джо, а какие - Фрэнку. Это обеспечивает гораздо более высокий уровень организации, чем отдельные переменные. Более того, поскольку члены Джо и Фрэнка имеют одинаковые имена, это обеспечивает согласованность для нескольких переменных одного и того же типа структуры.

Переменные-члены структуры действуют как обычные переменные, поэтому с ними можно выполнять обычные операции:

int total Возраст {joe.age + frank.age};

if (joe.wage> frank.wage)

std :: cout << "Джо зарабатывает больше, чем Фрэнк \ n";

else if (joe.wage

std :: cout << "Джо зарабатывает меньше, чем Фрэнк \ n";

else

std :: cout << "Джо и Фрэнк заработали одинаковую сумму \ n";

// Фрэнк получил повышение по службе

франк. Заработная плата + = 2,50;

// Сегодня день рождения Джо

++ Джо.возраст; // использовать предварительное приращение, чтобы увеличить возраст Джо на 1

Инициализация структур

Инициализация структур путем присвоения значений члену за членом немного обременительна, поэтому C ++ поддерживает более быстрый способ инициализации структур с использованием списка инициализаторов . Это позволяет вам инициализировать некоторые или все члены структуры во время объявления.

struct Employee

{

int id {};

int age {};

двойная заработная плата {};

};

Сотрудник Джо {1, 32, 60000.0}; // joe.id = 1, joe.age = 32, joe.wage = 60000.0

Сотрудник frank {2, 28}; // frank.id = 2, frank.age = 28, frank.wage = 0,0 (инициализация по умолчанию)

Если список инициализаторов не содержит инициализатора для некоторых элементов, эти элементы инициализируются значением по умолчанию (которое обычно соответствует нулевому состоянию для этого типа). В приведенном выше примере мы видим, что frank.wage по умолчанию инициализируется значением 0,0, поскольку мы не указали для него явное значение инициализации.

Инициализация нестатического элемента

Можно дать нестатическим (нормальным) элементам структуры значение по умолчанию:

struct Rectangle

{

двойной длины {1.0};

двойная ширина {1.0};

};

int main ()

{

Прямоугольник x {}; // длина = 1.0, ширина = 1.0

x.длина = 2,0; // вы можете присвоить другие значения, как обычные

return 0;

}

Если предусмотрены как инициализатор нестатического члена, так и инициализация списка, инициализация списка имеет приоритет.

struct Rectangle

{

двойной длины {1.0};

двойная ширина {1.0};

};

int main ()

{

Прямоугольник x {2.0, 2.0};

возврат 0;

}

В приведенном выше примере Rectangle x будет инициализирован с длиной и шириной 2,0.

Мы поговорим о том, что такое статические элементы, в следующей главе. А пока не беспокойтесь о них.

Присвоение структурам

Если мы хотим присвоить значения членам структур, мы можем сделать это индивидуально:

struct Employee

{

int id {};

int age {};

двойная заработная плата {};

};

Сотрудник Джо {};

Джо.id = 1;

joe.age = 32;

joe.wage = 60000.0;

Если вы хотите присвоить новое значение всем членам, это затруднительно, особенно для структур с большим количеством членов. Вы также можете назначать значения членам структур, используя список инициализаторов:

struct Employee

{

int id {};

int age {};

двойная заработная плата {};

};

Сотрудник Джо {};

Джо = {1, 32, 60000.0};

// То же, что и

joe = Employee {1, 32, 60000.0};

// Также возможно скопировать все элементы из одной переменной в другую

Сотрудник emma {joe};

Структуры и функции

Большим преимуществом использования структур перед отдельными переменными является то, что мы можем передать всю структуру функции, которая должна работать с членами:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

30

#include

struct Employee

{

int id {};

int age {};

двойная заработная плата {};

};

void printInformation (Сотрудник сотрудник)

{

std :: cout << "ID:" << сотрудник.id << '\ n';

std :: cout << "Возраст:" << employee.age << '\ n';

std :: cout << "Заработная плата:" << employee.wage << '\ n';

}

int main ()

{

Сотрудник Джо {14, 32, 24.15};

Франк служащего {15, 28, 18.27};

// Распечатать информацию о Джо

printInformation (joe);

std :: cout << '\ n';

// Распечатать информацию Фрэнка

printInformation (frank);

возврат 0;

}

В приведенном выше примере мы передаем всю структуру Employee в printInformation () (по значению, что означает, что аргумент копируется в параметр).Это избавляет нас от необходимости передавать каждую переменную индивидуально. Более того, если мы когда-нибудь решим добавить новые члены в нашу структуру Employee, нам не придется изменять объявление функции или вызов функции!

Вышеуказанная программа выводит:

 ID: 14
Возраст: 32 года
Заработная плата: 24.15

ID: 15
Возраст: 28
Заработная плата: 18,27
 

Функция также может возвращать структуру, что является одним из немногих способов заставить функцию возвращать несколько переменных.

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

000

34

35

36

37

38

39

40

41

42

#include

struct Point3d

{

double x {};

двойной у {};

двойной z {};

};

Point3d getZeroPoint ()

{

// Мы можем создать переменную и вернуть ее.

Point3d temp {0,0, 0,0, 0,0};

обратная температура;

}

Point3d getZeroPoint2 ()

{

// Мы можем вернуться напрямую. Мы уже указали тип

// в объявлении функции (Point3d), поэтому здесь нам не нужно снова

//.

возврат {0,0, 0,0, 0,0};

}

Point3d getZeroPoint3 ()

{

// Мы можем использовать пустые фигурные скобки для инициализации нулями всех

// членов `Point3d`.

возврат {};

}

int main ()

{

Point3d zero {getZeroPoint ()};

if (zero.x == 0.0 && zero.y == 0.0 && zero.z == 0.0)

std :: cout << "Точка равна нулю \ n";

else

std :: cout << "Точка не равна нулю \ n";

возврат 0;

}

Это отпечатки:

 Точка равна нулю
 

Вложенные структуры

Структуры могут содержать другие структуры.Например:

struct Employee

{

int id {};

int age {};

двойная заработная плата {};

};

struct Company

{

Сотрудник Генеральный директор {}; // Сотрудник - это структура внутри компании struct

int numberOfEmployees {};

};

Компания myCompany;

В этом случае, если мы хотим узнать, какова зарплата генерального директора, мы просто дважды используем оператор выбора участников: myCompany.CEO.wage;

Это выбирает члена генерального директора из myCompany, а затем выбирает члена заработной платы из генерального директора.

Вы можете использовать вложенные списки инициализаторов для вложенных структур:

struct Employee

{

int id;

int age;

двойная заработная плата;

};

struct Company

{

Сотрудник Генеральный директор; // Сотрудник - это структура внутри компании struct

int numberOfEmployees;

};

Компания myCompany {{1, 42, 60000.0}, 5};

Размер структуры и выравнивание структуры данных

Обычно размер структуры - это сумма размеров всех ее членов, но не всегда!

Рассмотрим структуру Employee, но с целыми числами фиксированного размера и значением id, равным половине размера age. На многих платформах double составляет 8 байтов, поэтому мы ожидаем, что Employee будет 2 + 4 + 8 = 14 байтов. Чтобы узнать точный размер Employee, мы можем использовать оператор sizeof:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

#include

#include

struct Employee

{

// Мы используем целые числа фиксированной ширины для примера.

// Избегайте их в реальном коде.

std :: int16_t id {};

std :: int32_t age {};

двойная заработная плата {};

};

int main ()

{

std :: cout << "Размер двойника: << << sizeof (double) << '\ n';

std :: cout << "Размер сотрудника равен" << sizeof (Сотрудник) << '\ n';

возврат 0;

}

На машине автора это отпечатано:

 Размер двойного - 8
Размер сотрудника 16
 

Оказывается, мы можем только сказать, что размер структуры будет на , по крайней мере, на больше, чем размер всех содержащихся в ней переменных.Но могло быть и больше! По соображениям производительности компилятор иногда добавляет пробелы в структуры (это называется padding ).

В приведенной выше структуре Employee компилятор невидимо добавляет 2 байта заполнения после идентификатора члена, делая размер структуры 16 байтов вместо 14. Причина, по которой он это делает, выходит за рамки данного руководства, но читатели, которые хотят подробнее можно прочитать о выравнивании структуры данных в Википедии. Это необязательное чтение и не требуется для понимания структур или C ++!

Доступ к структурам в нескольких файлах

Поскольку объявления структуры не занимают никакой памяти, если вы хотите совместно использовать объявление структуры в нескольких файлах (чтобы вы могли создавать экземпляры переменных этого типа структуры в нескольких файлах), поместите объявление структуры в файл заголовка и #include этот заголовок файл в любом месте, где вам это нужно.

Структурные переменные подчиняются тем же правилам, что и обычные переменные. Следовательно, чтобы сделать структурную переменную доступной для нескольких файлов, вы можете использовать ключевое слово extern в объявлении в заголовке и определить переменную в исходном файле.

Заключительные примечания к структурам

Структуры очень важны в C ++, так как понимание структур - это первый важный шаг к объектно-ориентированному программированию! Позже в этих руководствах вы узнаете о другом типе агрегированных данных, называемом классом, который построен на основе структур.Хорошее понимание структур поможет значительно упростить переход к классам.

Структуры, представленные в этом уроке, иногда называются простыми старыми структурами данных (или структурами POD), поскольку все члены являются членами данных (переменных). В будущем (когда мы будем обсуждать классы) мы поговорим о других типах участников.

Время викторины

У вас есть веб-сайт, и вы пытаетесь отслеживать, сколько денег вы зарабатываете в день на рекламе. Объявите рекламную структуру, которая отслеживает, сколько объявлений вы показывали читателям, какой процент объявлений нажимали пользователи и сколько вы в среднем зарабатывали на каждом клике по объявлению.Считайте значения для каждого из этих полей от пользователя. Передайте рекламную структуру функции, которая печатает каждое из значений, а затем вычисляет, сколько вы заработали за этот день (умножьте все 3 поля вместе).

Показать решение

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

000

34

35

36

37

38

39

40

41

42

#include

// Сначала нам нужно определить нашу структуру Advertising

struct Advertising

{

int adsShown {};

double clickThroughRatePercentage {};

двойное среднееEarningsPerClick {};

};

Реклама getAdvertising ()

{

Время рекламы {};

std :: cout << "Сколько объявлений было показано сегодня?";

std :: cin >> temp.adsShown;

std :: cout << "Какой процент рекламных объявлений был нажат пользователями?";

std :: cin >> temp.clickThroughRatePercentage;

std :: cout << "Какой был средний доход на клик?";

std :: cin >> temp.averageEarningsPerClick;

обратная температура;

}

void printAdvertising (Рекламное объявление)

{

std :: cout << "Количество показанных объявлений:" << ad.adsShown << '\ n';

std :: cout << "Рейтинг кликов:" << ad.clickThroughRatePercentage << '\ n';

std :: cout << "Средний доход за клик: $" << ad.averageEarningsPerClick << '\ n';

// Следующая строка разделена для уменьшения длины

// Нам нужно разделить ad.clickThroughRatePercentage на 100, потому что это процент от 100, а не множитель

std :: cout << "Total Earnings : $ "<<

(ad.adsShown * ad.clickThroughRatePercentage / 100 * ad.averageEarningsPerClick) << '\ n';

}

int main ()

{

// Объявление структурной переменной Advertising

Advertising ad {getAdvertising ()};

печатьРеклама (реклама);

возврат 0;

}

Создайте структуру для хранения дроби. Структура должна иметь целочисленный числитель и целочисленный знаменатель.Объявите 2 дробные переменные и прочтите их от пользователя. Напишите функцию под названием multiply, которая берет обе дроби, умножает их вместе и возвращает результат в виде десятичного числа. Вам не нужно сокращать дробь до наименьшего значения. Выведите результат умножения двух дробных переменных.

Показать решение

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

000

34

35

36

37

#include

struct Fraction

{

int числитель {};

целочисленный знаменатель {};

};

Дробь getFraction ()

{

Темп. Фракции {};

std :: cout << "Введите значение числителя:";

std :: cin >> temp.числитель;

std :: cout << "Введите значение знаменателя:";

std :: cin >> temp.denominator;

std :: cout << '\ n';

обратная температура;

}

двойное умножение (дробь f1, дробь f2)

{

// Не забывайте статическое приведение, иначе компилятор выполнит целочисленное деление!

return (static_cast (f1.numerator * f2.numerator) / (f1.denominator * f2.знаменатель));

}

int main ()

{

// Выделить нашу первую дробь

const Fraction f1 {getFraction ()};

const Fraction f2 {getFraction ()};

const double result {multiply (f1, f2)};

std :: cout << результат << '\ n';

возврат 0;

}

объявлений структуры | Документы Microsoft

  • 4 минуты на чтение

В этой статье

«Объявление структуры» именует тип и определяет последовательность значений переменных (называемых «членами» или «полями» структуры), которые могут иметь разные типы.Необязательный идентификатор, называемый «тегом», дает имя типа структуры и может использоваться в последующих ссылках на тип структуры. Переменная этого структурного типа содержит всю последовательность, определенную этим типом. Структуры в C похожи на типы, известные как «записи» в других языках.

Синтаксис

спецификатор структуры или объединения :
структура или объединение идентификатор opt { список деклараций структуры }
структура или объединение идентификатор 9000

структура или объединение :
структура
объединение

список-деклараций структуры :
декларация структуры
список деклараций структуры декларация структуры

декларация структуры :
список спецификаторов спецификаторов список деклараторов структуры ;

спецификатор-квалификатор-список :
тип-спецификатор спецификатор-квалификатор-список opt
тип-квалификатор спецификатор-квалификатор-список opt

struct-declarator-list :
struct-declarator-list struct-declarator-list , struct-declarator

структура-декларатор :
декларатор
тип-спецификатор декларатор opt : константное выражение

Объявление типа структуры не выделяет пространство для структуры.Это всего лишь шаблон для последующего объявления структурных переменных.

Ранее определенный идентификатор (тег) может использоваться для ссылки на тип структуры, определенный в другом месте. В этом случае список-деклараций-структур не может быть повторен, пока определение является видимым. Объявления указателей на структуры и определения типов для структурных типов могут использовать тег структуры до определения типа структуры. Однако определение структуры должно быть встречено до любого фактического использования размера полей.Это неполное определение типа и тега типа. Чтобы это определение было завершено, определение типа должно появиться позже в той же области.

Список деклараций структуры определяет типы и имена элементов структуры. Аргумент список-деклараций-структур содержит одно или несколько объявлений переменных или битовых полей.

Каждая переменная, объявленная в списке-декларации-структуры , определена как член типа структуры. Объявления переменных в списке-объявлении-структуре имеют ту же форму, что и объявления других переменных, обсуждаемых в этом разделе, за исключением того, что объявления не могут содержать спецификаторы или инициализаторы класса хранения.Члены структуры могут иметь любые типы переменных, кроме типа void , неполного типа или типа функции.

Нельзя объявить член имеющим тот тип структуры, в которой он появляется. Однако член может быть объявлен как указатель на тип структуры, в которой он появляется, если этот тип структуры имеет тег. Это позволяет создавать связанные списки структур.

Структуры имеют ту же область видимости, что и другие идентификаторы. Идентификаторы структуры должны отличаться от других тегов структуры, объединения и перечисления с такой же видимостью.

Каждая декларация структуры в списке декларации структуры должна быть уникальной в пределах списка. Однако имена идентификаторов в списке деклараций структуры не обязательно должны отличаться от обычных имен переменных или идентификаторов в других списках деклараций структуры.

К вложенным структурам также можно обращаться, как если бы они были объявлены на уровне файловой области. Например, с учетом этого объявления:

  структура
{
    int x;
    структура b
    {
      int y;
    } var2;
} var1;
  

обе эти декларации являются законными:

  struct a var3;
struct b var4;
  

Примеры

Эти примеры иллюстрируют объявления структур:

  struct employee / * Определяет структурную переменную с именем temp * /
{
    имя символа [20];
    int id;
    длинный класс;
} темп;
  

Структура сотрудника состоит из трех членов: name , id и class .Элемент name представляет собой массив из 20 элементов, а id и class являются простыми элементами с типом int и long соответственно. Идентификатор сотрудника - это структурный идентификатор.

  структурный сотрудник студент, профессорско-преподавательский состав, персонал;
  

В этом примере определены три структурные переменные: студент , преподаватель и сотрудник . Каждая структура имеет одинаковый список из трех членов.Объявляется, что члены имеют тип структуры employee , определенный в предыдущем примере.

  struct / * Определяет анонимную структуру и * /
{/ * структурная переменная с именем комплекс * /
    float x, y;
} сложный;
  

Комплекс Структура состоит из двух элементов с типом с плавающей запятой , x и y . Тип структуры не имеет тега и поэтому является безымянным или анонимным.

  struct sample / * Определяет структуру с именем x * /
{
    char c;
    float * pf;
    struct sample * next;
} Икс;
  

Первые два члена структуры - это переменная char и указатель на значение с плавающей запятой .Третий член, следующий за , объявлен как указатель на определяемый тип структуры (, образец ).

Анонимные структуры могут быть полезны, когда указанный тег не нужен. Это тот случай, когда одно объявление определяет все экземпляры структуры. Например:

  структура
{
    int x;
    int y;
} mystruct;
  

Встроенные структуры часто анонимны.

  struct somestruct
{
    struct / * анонимная структура * /
    {
        int x, y;
    } точка;
    тип int;
} w;
  

Специально для Microsoft

Компилятор допускает использование массива без размера или нулевого размера в качестве последнего члена структуры.Это может быть полезно, если размер постоянного массива отличается при использовании в различных ситуациях. Объявление такой структуры выглядит так:

struct идентификатор { набор объявлений тип имя-массива []; };

Массивы без размера могут появляться только как последний член структуры. Структуры, содержащие объявления массивов без размера, могут быть вложены в другие структуры до тех пор, пока никакие другие члены не объявлены ни в одной из включающих структур.Массивы таких структур не допускаются. Оператор sizeof , применяемый к переменной этого типа или к самому типу, предполагает 0 для размера массива.

Объявления структур также могут быть указаны без декларатора, если они являются членами другой структуры или объединения. Имена полей продвигаются во вложенную структуру. Например, безымянная структура выглядит так:

  структур
{
    float y;
    структура
    {
        int a, b, c;
    };
    char str [10];
} * p_s;
..
.
p_s-> b = 100; / * Ссылка на поле в структуре s * /
  

Информацию о ссылках на структуры см. В разделе «Структура и члены союза».

END Специфические для Microsoft

См. Также

Деклараторы и объявления переменных

Сопоставление типов структур и объединений из C - учебник

Это второй пост в серии. Самый первый учебник из этой серии - Отображение примитивных типов данных из C.Также есть указатели функций сопоставления из руководств по C и сопоставление строк из руководств C.

В этом руководстве вы узнаете:

Сопоставление структур и объединений типов C

Лучший способ понять сопоставление между Kotlin и C - это попробовать небольшой пример. Мы объявим структуру и объединение на языке C, чтобы увидеть, как они отображаются в Kotlin.

Kotlin / Native поставляется с инструментом cinterop , инструмент генерирует привязки между языком C и Kotlin.Он использует файл .def , чтобы указать библиотеку C для импорта. Более подробная информация обсуждается в учебнике «Взаимодействие с библиотеками C.

В предыдущем руководстве вы создали файл lib.h . На этот раз включите эти объявления непосредственно в файл interop.def после разделительной строки --- :

---

typedef struct {
int a;
двойной б;
} MyStruct;

void struct_by_value (MyStruct s) {}
void struct_by_pointer (MyStruct * s) {}

typedef union {
int a;
MyStruct b;
float c;
} MyUnion;

void union_by_value (MyUnion u) {}
void union_by_pointer (MyUnion * u) {}

Интерфейс .def достаточно для компиляции и запуска приложения или открытия его в среде IDE. Пришло время создать файлы проекта, открыть проект в IntelliJ IDEA и запустить его.

Проверить сгенерированные API Kotlin для библиотеки C

Хотя можно использовать командную строку напрямую или путем объединения ее с файлом сценария (например, .sh или .bat ), этот подход не работает. плохо масштабируется для больших проектов с сотнями файлов и библиотек. Тогда лучше использовать компилятор Kotlin / Native с системой сборки, поскольку он помогает загружать и кэшировать двоичные файлы и библиотеки компилятора Kotlin / Native с транзитивными зависимостями и запускать компилятор и тесты.Kotlin / Native может использовать систему сборки Gradle через плагин kotlin-multiplatform.

Мы рассмотрели основы настройки IDE-совместимого проекта с Gradle в учебнике A Basic Kotlin / Native Application. Пожалуйста, проверьте его, если вы ищете подробные первые шаги и инструкции о том, как запустить новый проект Kotlin / Native и открыть его в IntelliJ IDEA. В этом руководстве мы рассмотрим расширенное использование Kotlin / Native, связанное с взаимодействием с C, и многоплатформенные сборки с Gradle.

Сначала создайте папку проекта. Все пути в этом руководстве будут относиться к этой папке. Иногда недостающие каталоги необходимо создать до того, как можно будет добавить какие-либо новые файлы.

Используйте следующий файл сборки build.gradle (.kts) Gradle:

plugins {
id 'org.jetbrains.kotlin.multiplatform' версия '1.4.32'
}

репозитории {
mavenCentral ()
}

kotlin {
linuxX64 ('native') {// в Linux
// macosX64 ('native') {// в macOS
// mingwX64 ('native') {// в Windows
сборники.main.cinterops {
взаимодействие
}

двоичные файлы {
исполняемый файл ()
}
}
}

wrapper {
gradleVersion = '6.7.1'
distributionType = 'BIN'
}

плагины {
котлин ("мультиплатформенная") версия "1.4.32"
}

репозитории {
mavenCentral ()
}

kotlin {
linuxX64 ("native") {// в Linux
// macosX64 ("native") {// в macOS
// mingwX64 ("native") {// в Windows
val main от compilations.getting
val взаимодействие от main.cinterops.creating

двоичные файлы {
исполняемый файл ()
}
}
}

задачи.wrapper {
gradleVersion = "6.7.1"
distributionType = Wrapper.DistributionType.BIN
}

Подготовленные исходные коды проекта можно напрямую загрузить с Github:

Файл проекта настраивает взаимодействие C в качестве дополнительного шага сборки. Давайте переместим файл interop.def в каталог src / nativeInterop / cinterop . Gradle рекомендует использовать соглашения вместо конфигураций, например, исходные файлы должны находиться в папке src / nativeMain / kotlin .По умолчанию все символы из C импортируются в пакет interop , вы можете импортировать весь пакет в наши файлы .kt . Ознакомьтесь с документацией плагина kotlin-multiplatform, чтобы узнать обо всех различных способах его настройки.

Создайте файл-заглушку src / nativeMain / kotlin / hello.kt со следующим содержимым, чтобы увидеть, как объявления C видны из Kotlin:

import interop. *

fun main () {
println ("Привет, Котлин / Родной!")

struct_by_value (/ * исправь меня * /)
struct_by_pointer (/ * исправь меня * /)
union_by_value (/ * исправь меня * /)
union_by_pointer (/ * исправь меня * /)
}

Теперь вы готовы открыть проект в IntelliJ IDEA и посмотреть, как исправить пример проекта.При этом посмотрите, как примитивные типы C отображаются в Kotlin / Native.

Примитивные типы в Kotlin

С помощью IntelliJ IDEA Перейти к | Объявление или ошибки компилятора, вы видите следующий сгенерированный API для функций C, struct и union :

fun struct_by_value (s: CValue )
fun struct_by_pointer (s: CValuesRef ?)

весело union_by_value (u: CValue )
fun union_by_pointer (u: CValuesRef ?)

конструктор класса MyStruct (rawPtr: NativePtr / * = NativePtr * /): CStructVar {
var a: Int
var b: Double
сопутствующий объект: CStructVar.Тип
}

конструктор класса MyUnion (rawPtr: NativePtr / * = NativePtr * /): CStructVar {
var a: Int
val b: MyStruct
var c: Float
сопутствующий объект: CStructVar.Type
}

Вы видите, что cinterop сгенерировал типы оболочки для наших типов struct и union . Для объявлений типов MyStruct и MyUnion в C создаются классы Kotlin MyStruct и MyUnion соответственно. Оболочки наследуются от базового класса CStructVar и объявляют все поля как свойства Kotlin.Он использует CValue для представления параметра структуры по значению и CValuesRef? , чтобы представить передачу указателя на структуру или объединение.

Технически нет разницы между типами struct и union на стороне Kotlin. Обратите внимание, что свойства a , b и c класса MyUnion в Kotlin используют одно и то же место в памяти для чтения / записи своего значения, точно так же, как union на языке C.

Более подробная информация и расширенные варианты использования представлены в документации
C Interop

Используйте типы структур и объединений из Kotlin

Сгенерированные классы-оболочки для типов C struct и union из Kotlin легко использовать. Благодаря сгенерированным свойствам кажется естественным использовать их в коде Kotlin. Пока что единственный вопрос - как создать новый экземпляр для этих классов. Как видно из объявлений MyStruct и MyUnion , их конструкторам требуется NativePtr .Конечно, вы не хотите иметь дело с указателями вручную. Вместо этого вы можете использовать Kotlin API для создания экземпляров этих объектов для нас.

Давайте посмотрим на сгенерированные функции, которые принимают наши MyStruct и MyUnion в качестве параметров. Вы видите, что параметры по значению представлены как kotlinx.cinterop.CValue . А для параметров типизированного указателя вы видите kotlinx.cinterop.CValuesRef . Kotlin предоставляет нам API, чтобы легко работать с обоими типами, давайте попробуем и посмотрим.

Создайте CValue

CValue Тип используется для передачи параметров по значению в вызов функции C. Используйте функцию cValue , чтобы создать экземпляр объекта CValue . Функция требует лямбда-функции с приемником для инициализации базового типа C. Функция объявлена ​​следующим образом:

fun cValue (initialize: T. () -> Unit): CValue

Теперь пора посмотреть, как использовать cValue и передавать параметры по значению:

fun callValue () {

val cStruct = cValue {
а = 42
б = 3.14
}
struct_by_value (cStruct)

val cUnion = cValue {
b.a = 5
b.b = 2,7182
}

union_by_value (cUnion)
}

Создать структуру и объединение как CValuesRef

CValuesRef Тип используется в Kotlin для передачи параметра типизированного указателя функции C. Во-первых, вам понадобится экземпляр классов MyStruct и MyUnion . Создавайте их прямо в родной памяти. Используйте

fun alloc (): T

Функция расширения

на kotlinx.cinterop.NativePlacement для этого.

NativePlacement представляет внутреннюю память с функциями, аналогичными malloc и free . Существует несколько реализаций NativePlacement . Глобальный вызывается с помощью kotlinx.cinterop.nativeHeap и не забудьте вызвать функцию nativeHeap.free (..) , чтобы освободить память после использования.

Другой вариант - использовать

fun memScoped (block: kotlinx.cinterop.MemScope. () -> R): R

функция. Он создает краткосрочную область выделения памяти, и все выделения будут очищены автоматически в конце блока .

Ваш код для вызова функций с указателями будет выглядеть так:

fun callRef () {
memScoped {
val cStruct = alloc ()
cStruct.a = 42
cStruct.b = 3,14

struct_by_pointer (cStruct.ptr)

val cUnion = alloc ()
cUnion.b.a = 5
cUnion.b.b = 2,7182

union_by_pointer (cUnion.ptr)
}
}

Обратите внимание, что этот код использует свойство расширения ptr , которое происходит от типа приемника лямбда memScoped , чтобы превратить экземпляры MyStruct и MyUnion в собственные указатели.

Классы MyStruct и MyUnion имеют указатель на внутреннюю память внизу. Память будет освобождена, когда функция memScoped завершится, что равно концу ее блока .Убедитесь, что указатель не используется вне вызова memScoped . Вы можете использовать Arena () или nativeHeap для указателей, которые должны быть доступны дольше или кэшируются внутри библиотеки C.

Преобразование между CValue и CValuesRef

Конечно, бывают случаи использования, когда вам нужно передать структуру в качестве значения одному вызову, а затем передать ту же структуру в качестве ссылки на другой вызов. Это возможно и в Kotlin / Native. Здесь потребуется NativePlacement .

Давайте теперь посмотрим, CValue сначала превращается в указатель:

fun callMix_ref () {
val cStruct = cValue {
а = 42
б = 3,14
}

memScoped {
struct_by_pointer (cStruct.ptr)
}
}

Этот код использует свойство расширения ptr , которое происходит от типа лямбда-приемника memScoped , чтобы превратить экземпляры MyStruct и MyUnion в собственные указатели. Эти указатели действительны только внутри блока memScoped .

Для обратного преобразования, чтобы превратить указатель в переменную по значению, мы вызываем функцию расширения readValue () :

fun callMix_value () {
memScoped {
val cStruct = alloc ()
cStruct.a = 42
cStruct.b = 3,14

struct_by_value (cStruct.readValue ())
}
}

Выполните код

Теперь, когда вы узнали, как использовать объявления C в своем коде, вы готовы опробовать это на реальном примере. Давайте исправим код и посмотрим, как он работает, вызвав задачу runDebugExecutableNative Gradle в среде IDE или используя следующую консольную команду:

./ gradlew runDebugExecutableNative

Последний код в файле hello.kt может выглядеть следующим образом:

import interop. *
импорт kotlinx.cinterop.alloc
import kotlinx.cinterop.cValue
import kotlinx.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *