Typedef c что это
Псевдонимы и определения типов (C++)
Объявление псевдонима можно использовать для объявления имени, которое будет использоваться в качестве синонима для ранее объявленного типа. (Этот механизм также называется псевдонимом типа). Этот механизм также можно использовать для создания шаблона псевдонима, который может быть особенно полезен для пользовательских распределительов.
Синтаксис
Примечания
identifier
Имя псевдонима.
type
Идентификатор типа, для которого создается псевдоним.
Псевдоним не вводит в программу новый тип и не может менять значение существующего имени типа.
Простейшая форма псевдонима эквивалентна typedef механизму из c++ 03:
Псевдонимы также работают с указателями на функции, но гораздо удобнее для чтения, чем эквивалентное определение типа:
Ограничением typedef механизма является то, что оно не работает с шаблонами. Напротив, синтаксис псевдонима типа в C ++11 позволяет создавать шаблоны псевдонимов:
Пример
Определения типов
Объявления typedef можно использовать для создания более коротких или более понятных имен для типов, уже определенных в языке или объявленных пользователем. Имена typedef позволяют инкапсулировать детали реализации, которые могут измениться.
При объявлении в локальной области идентификатора с тем же именем, что и имя typedef, или при объявлении члена структуры либо объединения в той же области или во внутренней области обязательно должен указываться спецификатор типа. Пример:
Чтобы повторно использовать имя FlagType для идентификатора, члена структуры или члена объединения, необходимо указать тип:
поскольку FlagType воспринимается как часть типа, а не как заново объявляемый идентификатор. Это объявление недопустимо, как и
С помощью typedef можно объявить любой тип, включая типы указателей, функций и массивов. Имя typedef для типа указателя на структуру или объединение можно объявить до определения типа структуры или объединения, если только определение находится в той же области видимости, что и объявление.
Примеры
Использование typedef объявлений состоит в том, чтобы сделать объявления более однородными и компактными. Пример:
Чтобы использовать typedef для указания фундаментальных и производных типов в одном объявлении, можно разделить деклараторы запятыми. Пример:
В следующем примере задан тип DRAWF для функции, не возвращающей никакого значения и принимающей два аргумента int.
После оператора выше typedef объявление
будет эквивалентно следующему:
typedef часто объединяется с struct для объявления и именования определяемых пользователем типов:
Повторное объявление определений типов
typedef Объявление можно использовать для повторного объявления того же имени для ссылки на один и тот же тип. Пример:
typedef Невозможно переопределить имя, которое ранее было объявлено как другой тип. Таким образом, если file2. H содержит
компилятор выдает ошибку из-за попытки повторного объявления имени CHAR как имени другого типа. Это правило распространяется также на конструкции, подобные следующим:
определения типов в C++ и C
Преимущество такого объявления заключает в том, что можно выполнять объявления
В C++ разница между typedef именами и реальными типами (объявленными с class struct union enum ключевыми словами,, и) более Разна. Хотя методика C объявления структуры без имени в typedef инструкции по-прежнему работает, она не предоставляет преимуществ для нотаций, как это делается в c.
Имя (синоним) не может использоваться после class struct union префикса, или.
Имя не может использоваться в качестве имени конструктора или деструктора в объявлении класса.
Таким образом, этот синтаксис не предоставляет механизм наследования, создания или удаления.
Объявления Typedef
Объявление typedef — это объявление с typedef в качестве класса хранения. Декларатор становится новым типом. Объявления typedef можно использовать для создания более коротких или более понятных имен для типов, уже определенных в языке C или объявленных пользователем. Имена typedef позволяют инкапсулировать детали реализации, которые могут измениться.
Объявление typedef интерпретируется точно так же, как и объявление переменной или функции, но идентификатор становится синонимом типа, а не принимает тип, указанный в объявлении.
Синтаксис
declaration:
declaration-specifiers init-declarator-listopt;
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
storage-class-specifier:
typedef
type-specifier:
void
char
short
int
long
float
double
signed
unsigned
struct-or-union-specifier
enum-specifier
typedef-name
Имена Typedef используют то же пространство имен, что и обычные идентификаторы (дополнительные сведения см. в статье Пространства имен). Поэтому в программе может присутствовать имя typedef и идентификатор с тем же именем в локальной области. Пример:
При объявлении в локальной области идентификатора с тем же именем, что и имя typedef, или при объявлении члена структуры либо объединения в той же области или во внутренней области обязательно должен указываться спецификатор типа. Следующий пример иллюстрирует это ограничение:
Чтобы повторно использовать имя FlagType для идентификатора, члена структуры или члена объединения, необходимо указать тип:
поскольку FlagType воспринимается как часть типа, а не как заново объявляемый идентификатор. Это объявление недопустимо, как и
С помощью typedef можно объявить любой тип, включая типы указателей, функций и массивов. Имя typedef для типа указателя на структуру или объединение можно объявить до определения типа структуры или объединения, если только определение находится в той же области видимости, что и объявление.
Имена typedef можно использовать, чтобы сделать код более понятным. Все три следующих объявления signal задают один и тот же тип, причем в первом объявлении имена typedef не используются.
Примеры
В следующих примерах показаны объявления typedef:
В этом примере задан тип DRAWF для функции, не возвращающей никакого значения и принимающей два аргумента int. Это означает, например, что объявление
Урок №60. Псевдонимы типов: typedef и type alias
Обновл. 13 Сен 2021 |
На этом уроке мы рассмотрим псевдонимы типов typedef и type alias в языке C++.
typedef
Ключевое слово typedef позволяет программисту создать псевдоним для любого типа данных и использовать его вместо фактического имени типа. Чтобы объявить typedef (использовать псевдоним типа) — используйте ключевое слово typedef вместе с типом данных, для которого создается псевдоним, а затем, собственно, сам псевдоним. Например:
typedef не определяет новый тип данных. Это просто псевдоним (другое имя) для уже существующего типа. Его можно использовать везде, где используется обычный тип.
Даже если следующее не имеет смысла, оно все равно разрешено в языке C++:
typedef и читабельность кода
typedef используется в улучшении документации и разборчивости кода. Имена таких типов, как char, int, long, double и bool хороши для описания того, какой тип возвращает функция, но чаще всего мы хотим знать, с какой целью возвращается значение. Например, рассмотрим следующую функцию:
Мы видим, что возвращаемым значением является целое число, но что оно означает? Количество пропущенных вопросов? Идентификационный номер учащегося? Код ошибки? Сам int ни о чем нам не говорит. Исправим ситуацию:
С использованием возвращаемого типа testScore_t становится очевидным, что функция возвращает тип, значением которого является результат теста.
typedef и поддержка кода
typedef также позволяет изменить базовый тип объекта без внесения изменений в большое количество кода. Например, если вы использовали тип short для хранения идентификационного номера учащегося, но потом решили, что лучше использовать тип long, то вам придется прошерстить кучу кода для замены short на long. И, вероятно, было бы трудно определить, какой из типов short используется для хранения идентификационных номеров, а какой — для других целей.
typedef и кроссплатформенность
Еще одним большим преимуществом typedef является возможность скрывать специфические для определенных платформ (операционных систем) детали. На некоторых платформах тип int занимает 2 байта, на других — 4 байта. Таким образом, использование типа int для хранения более 2 байтов информации может быть потенциально опасным при написании кроссплатформенного кода.
Поскольку char, short, int и long не указывают свой размер, то для кроссплатформенных программ довольно часто используется typedef для определения псевдонимов, которые включают размер типа данных в битах. Например, int8_t — это 8-битный signed int, int16_t — это 16-битный signed int, а int32_t — это 32-битный signed int.
typedef и упрощение сложного
Хотя мы до сих пор рассматривали только простые типы данных, в языке C++ вы можете увидеть и следующие переменные/функции:
8.6 – typedef и псевдонимы типов
Ключевое слово typedef
По соглашению имена typedef объявляются с использованием суффикса » _t «. Это помогает указать, что идентификатор представляет собой тип, а не переменную или функцию, а также помогает предотвратить конфликты имен с другими типами идентификаторов.
Лучшая практика
После определения имя typedef можно использовать везде, где требуется тип. Например, мы можем создать переменную с именем typedef в качестве типа:
typedef не определяет новый тип
Обратите внимание, что typedef не определяет новый тип. Скорее, он просто создает новый идентификатор (псевдоним) для существующего типа. typedef можно использовать как замену везде, где можно использовать обычный тип.
Это позволяет нам делать вещи, которые синтаксически корректны, но семантически бессмысленны. Например:
Предупреждение
Следует проявлять осторожность, чтобы не смешивать значения псевдонимов типов, которые должны быть семантически разными.
В качестве отступления.
Область видимости typedef
Если вам нужно использовать один или несколько typedef в нескольких файлах, их можно определить в заголовочном файле и включить через #include в любые файлы исходного кода, которые должны использовать это определение:
Проблемы typedef
Однако у typedef есть несколько синтаксических проблем. Во-первых, легко забыть, что на первом месте: имя типа или определение типа. Что правильно?
Это легко перепутать. К счастью, в таких случаях компилятор пожалуется.
Во-вторых, синтаксис typedef становится уродливым при использовании более сложных типов, особенно указателей на функции (которые мы рассмотрим в уроке «11.9 – Указатели на функции»):
В приведенном выше определении typedef имя нового типа ( fcn_t ) скрыто в середине определения, что затрудняет чтение определения.
Псевдонимы типов
Чтобы помочь решить эти проблемы typedef был добавлен улучшенный синтаксис, имитирующий способ объявления переменных. Этот синтаксис называется псевдонимом типа (type alias).
Например, следующий typedef :
можно объявить как следующий псевдоним типа:
Лучшая практика
Когда мы должны использовать псевдонимы типов?
Теперь, когда мы рассмотрели, что такое typedef и псевдонимы типов, давайте поговорим о том, для чего они полезны.
Использование псевдонимов типов для кодирования, независимого от платформы
Одно из главных преимуществ псевдонимов типов заключается в том, что их можно использовать для скрытия деталей, специфичных для платформы. На некоторых платформах int составляет 2 байта, а на других – 4 байта. Таким образом, при написании кода, независимого от платформы, использование int для хранения более 2 байтов информации может быть потенциально опасным.
Чтобы гарантировать, что каждый псевдоним типа преобразуется в тип нужного размера, псевдонимы типа такого рода обычно используются в сочетании с директивами препроцессора:
Целочисленные типы фиксированной ширины (такие как std::int_fast16_t и std::int_least32_t ) и size_t (описанные в уроке «4.6 – Целочисленные типы фиксированной ширины и size_t ») – на самом деле псевдонимы для различных базовых типов!
Эта программа печатает:
Использование псевдонимов типов для упрощения сложных типов
Хотя до сих пор мы имели дело только с простыми типами данных, в продвинутом C++ типы могут быть сложными и длинными для ввода. Например, вы можете увидеть функцию и переменную, определенные следующим образом:
Ввод std::vector > везде, где вам нужно использовать этот тип, может оказаться громоздким. Гораздо проще использовать псевдоним типа:
Вероятно, это лучшее использование псевдонимов типов.
Использование псевдонимов типов для повышения читабельности
Псевдонимы типов также могут помочь в документации и понимании кода.
Например, рассмотрим следующую функцию:
Мы видим, что возвращаемое значение является целым числом, но что означает целое число? Буквенная оценка? Количество пропущенных вопросов? Идентификационный номер студента? Код ошибки? Кто знает! Тип возвращаемого значения int мало что говорит нам. Если нам повезет, где-то существует документация по этой функции, к которой мы можем обратиться. Если нам не повезет, мы должны прочитать код и определить назначение сами.
Теперь давайте создадим эквивалентную версию, используя псевдоним типа:
Использование типа возвращаемого значения testScore_t делает очевидным, что функция возвращает тип, представляющий результат теста.
По нашему опыту, создание псевдонима типа только для документирования типа возвращаемого значения отдельной функции не стоит усилий (вместо этого используйте комментарий). Но если вы уже создали typedef по другим причинам, это может быть приятным дополнительным преимуществом.
Использование псевдонимов типов для упрощения поддержки кода
Хотя это кажется приятным преимуществом, необходимо соблюдать осторожность при изменении типа, поскольку поведение программы также может измениться. Это особенно верно при изменении типа псевдонима типа на тип из другого семейства типов (например, целочисленный тип на значение с плавающей запятой или наоборот)! Новый тип может иметь проблемы со сравнением или делением целых чисел на числа с плавающей запятой или другие проблемы, которых не было у старого типа. Если вы измените существующий тип на какой-либо другой, ваш код следует тщательно повторно протестировать.
Минусы и заключение
Хотя псевдонимы типов предлагают некоторые преимущества, они также вводят в ваш код еще один идентификатор, который необходимо понимать. Если это не компенсируется какими-либо преимуществами для удобочитаемости или понимания, тогда псевдоним типа приносит больше вреда, чем пользы.
Плохо используемый псевдоним типа может взять знакомый тип (например, std::string ) и скрыть его за пользовательским именем, которое необходимо найти. В некоторых случаях (например, с умными указателями, которые мы рассмотрим в будущей главе) скрытие информации о типе также может быть вредным для понимания того, как этот тип должен работать.
По этой причине псевдонимы типов следует использовать в первую очередь в тех случаях, когда есть явное преимущество для читабельности или поддерживаемости кода. Это в большей степени искусство, чем наука. Псевдонимы типов наиболее полезны, когда их можно использовать во многих местах кода, а не в меньшем количестве мест.
Лучшая практика
Разумно используйте псевдонимы типов, если они дают явное преимущество для читабельности или поддерживаемости кода.
Небольшой тест
Вопрос 1
Возьмем следующий прототип функции:
C Урок 24. Перечисляемый тип. Директива typedef
В уроке 13 мы познакомились с константами, как они объявляются и используются в программе. Мы помним, что это такие данные, которые в ходе программы изменить невозможно и они сохраняют своё значения до окончания своего существования.
Только может наступить такая ситуация, что констант программе потребуется слишком много и под них потребуется слишком много имён и, самое главное, слишком много значений. В таких значениях мы в конце концов запутаемся и рискуем объявить несколько констант с одним и тем же значением. Тогда, скорей всего, неизбежны ошибки, если эти константы будут использоваться для какой-то одной задачи. Конечно, можно объявить константный массив, но тогда не будет уникальных имён под каждый элемент, а по индексу порой не совсем понятно, что значит тот или иной элемент и для чего он будет служить в нашей программе.
Оказывается, что для такой ситуации также есть решение. Это перечисляемый тип для констант, который позволяет нам объявить для какой-то одной задачи сразу несколько констант с уникальными именами, не заботясь об уникальности их значений. Для объявления перечисляемого типа или, как его попросту называют, перечисления служит вот такая конструкция
Это общая форма конструкции enum. Данная конструкция, обозначающая перечисляемый тип, начинается с ключевого слова enum, Затем следует имя перечисляемого типа, а далее идёт блок, в котором через запятую перечисляются имена констант, причём можно данным константам присвоить значение целого типа сразу, а если его не присвоить (квадратные скобки означают то, что параметры необязательные и могут отсутствовать), то оно присвоится автоматически. Данное значение тогда будет равно значению предыдущей константы в данном списке, увеличенному на единицу. Если мы даже самой первой константе в списке также не присвоим значение, то оно примет значение – 0 (ноль).
Вот так практически мы можем объявить перечисляемый тип
enum eColor
Так как здесь мы ничего не присваиваем нашим элементам перечисления, которые, кстати, называются перечислителями, то их значения будут 0, 1 и 2.
После такого объявления мы можем объявлять переменные с такими именами в нашей программе, только перед именем типа данных нужно будет обязательно писать ключевое слово enum
enum eColor clr;
Думаю, что более понятно вам станет по данному типу тогда, когда мы его проработаем практически в исходном коде.
Теперь #typegef. Как известно, в языке C любые данные имеют какой-то тип. Каждый такой тип имеет своё имя, например, int, float и т.д. Также порой бывают такие моменты, когда нам нужно объявить в нашем коде какой-то свой тип и присвоить ему какое-то имя. Для этого и служит директива #typedef.
С помощью данной директивы мы можем дать стандартному типу данных своё имя, для этого существует вот такая общая форма объявления пользовательского типа данных
Например, мы хотим типу float назначить какое-то своё имя
typedef float double_32 ;
После данного объявления имя double_32 станет именем типа данных такого же, как и float и его спокойно можно будет использовать в программе
double_32 d1;
d1 = 0.01;
Например, и перечисление мы тоже можем объявить через typedef
typedef enum
HIGHEST
> eSize ;
Теперь имя типа данных перечисляемого типа у нас будет после блока и объявлять в коде переменные данного типа мы можем теперь без ключевого слова enum
eSize var_Size = HIGH ;
Хотя, в принципе, ничего сложного в сегодняшней теме, вроде бы и нет, но всё же, считаю, что проработать её на практике мы просто обязаны.
Поэтому создадим проект из проекта прошлого урока с именем MYPROG23 и назовём его MYPROG24.
Как создавать проекты из других, не запортив оригинальные, мы с вами научились в прошлом уроке.