Wchar t
Широкий символ — это термин, относящийся к программированию. Он используется для обозначения символьного типа данных, который шире традиционных 8-битных символов. Это не то же самое, что Юникод.
wchar_t — это тип данных стандарта ANSI/ISO C (а также использующийся в других языках программирования) для представления широких символов.
Стандарт Unicode 4.0 говорит следующее:
«ANSI/ISO C оставляет семантику широких символов на усмотрение конкретной реализации»
«размер типа wchar_t определяется компилятором, вплоть до минимальных 8 бит. Соответственно, приложения, которым требуется сохранять переносимость на различных C и C++ компиляторах, не должны использовать wchar_t для хранения Unicode-текста. Тип wchar_t предназначен для хранения широких символов в том виде, в котором их понимают конкретные компиляторы, и это может не соответствовать Юникоду».
В Windows API, тип wchar_t имеет размер 16 бит. Windows API нарушает стандарт ANSI/ISO C, который требует, что бы символьный тип wchar_t поддерживал все представимые в системе символы в одном объекте wchar_t . Вместо этого, wchar_t в Windows представляет собой символы (либо часть символа) в кодировке Unix-системах тип wchar_t имеет размер 32 бита.
В библиотеке ANSI C за широкие символы отвечают заголовочные файлы <
Ссылки
Wikimedia Foundation . 2010 .
Смотреть что такое «Wchar t» в других словарях:
Wchar.h — Стандартная библиотека языка программирования С assert.h complex.h ctype.h errno.h fenv.h float.h inttypes.h iso646.h limits.h locale.h math.h setjmp.h signal.h stdarg.h stdbool.h stddef.h stdint.h stdio.h stdlib.h … Википедия
Wchar — Wchar: wchar t (широкий символ) символьный тип данных. wchar.h заголовочный файл стандартной библиотеки языка программирования Си. Содержит функции для работы с многобайтовыми и широкими символами … Википедия
wchar.h — For other uses, see WCHA (disambiguation). C Standard Library Data types Character classification Strings Mathematics File input/output … Wikipedia
wchar.h — Стандартная библиотека языка программирования С assert.h complex.h ctype.h errno.h fenv.h float.h inttypes.h iso646.h limits.h locale.h math.h setjmp.h signal.h stdarg.h stdbool.h stddef.h … Википедия
Широкий символ — Широкий символ это термин, относящийся к программированию. Он используется для обозначения символьного типа данных, который шире традиционных 8 битных символов. Это не то же самое, что Юникод. wchar t это тип данных стандарта ANSI/ISO … Википедия
C standard library — The C Standard Library consists of a set of sections of the ANSI C standard in the programming language C. They describe a collection of headers and library routines used to implement common operations such as input/output[1] and string handling … Wikipedia
Стандартная библиотека языка Си — Стандартная библиотека языка программирования С assert.h complex.h ctype.h errno.h fenv.h float.h inttypes.h iso646.h limits.h locale.h math.h setjmp.h signal.h stdarg.h stdbool.h stddef.h … Википедия
Wide character — A wide character is a computer character datatype that generally has a size greater than the traditional 8 bit character. The increased datatype size allows for the use of larger coded character sets. Contents 1 History 2 Relation to UCS and… … Wikipedia
Comparison of relational database management systems — Programming language comparisons General comparison Basic syntax Basic instructions Arrays Associative arrays String operations … Wikipedia
Bibliotheque standard de C — Bibliothèque standard de C La bibliothèque standard du C est une collection maintenant normalisée d en têtes et de routines utilisées pour implémenter des opérations courantes, telles que les entrées/sorties et la gestion des chaînes de… … Wikipédia en Français
Что такое TCHAR, WCHAR, LPSTR, LPWSTR,LPCTSTR (итд)

Многие C++ программисты, пишущие под Windows часто путаются над этими странными идентификаторами как TCHAR, LPCTSTR. В этой статье я попытаюсь наилучшим способом расставить все точки над И. И рассеять туман сомнений.
В свое время я потратил много времени копаясь в исходниках и не понимал что значат эти загадочные TCHAR, WCHAR, LPSTR, LPWSTR,LPCTSTR.
Недавно нашел очень грамотную статью и представляю ее качественный перевод.
Статья рекомендуется тем кто бессонными ночами копошиться в кодах С++.
Вам интересно ??
Прошу под кат.
В общем, символ строки может быть представлен в виде 1-го байта и 2-х байтов.
Обычно одно-байтовый символ это символ кодировки ANSI- в этой кодировке представлены все английские символы. А 2-х байтовый символ это кодировка UNICODE, в которой могут быть представлены все остальные языки в мире.
Компилятор Visual C++ поддерживает char и wchar_t как встроенные типы данных для кодировок ANSI и UNICODE.Хотя есть более конкретное определение Юникода, но для понимания, ОС Windows использует именно 2-х байтовую кодировку для много языковой поддержки приложений.
Что делать если вы хотите чтобы ваш С/С++ код был независимым от кодировок и использование разных режимов кодирования?
СОВЕТ. Используйте общие типы данных и имена для представления символов и строк.
Например, вместо того чтобы менять следующий код:
В целях поддержки многоязычных приложений (например, Unicode), вы можете писать код в более общей манере.
В настройках проекта на вкладке GENERAL есть параметр CHARACTER SET который указывает в какой кодировке будет компилироваться программа:

Если указан параметр «Use Unicode Character set», тип TCHAR будет транслироваться в тип wchar_t. Если указан параметр «Use Multi-byte character set» то тогда TCHAR будет транслироваться в тип char. Вы можете свободно использовать типы char и wchar_t, и настройки проекта никоим образом не повлияют на использование этих ключевых слов.
TCHAR определен так:
Макрос _UNICODE будет включен если вы укажите «Use Unicode Character set» и тогда тип TCHAR будет определен как wchar_t. Когда же вы укажите «Use Multi-byte character set» TCHAR будет определен как char.
Помимо этого, для того что была поддержка нескольких наборов символов используя общий базовый код, и возможно поддержки много языковых приложений, используйте Специфические функции (то есть макросы).
Вместо того чтобы использовать strcpy, strlen, strcat (в том числе защищенные варианты функции с префиксом _s), или wcscpy, wcslen, wcscat (включая защищенные варианты), вам лучше использовать функции _tcscpy, _tcslen, _tcscat.
Как вы знаете функция strlen описана так:
И функция wcslen описана так:
Вам лучше использовать _tcslen, который логически описан так:
WC это Wide Character (Большой символ). Поэтому, wcs функции будут для wide-character-string (то есть для большой-символьной-строки).Таким образом _tcs будет означать _T символьная строка. И как вы знаете строки с префиксом _T могут быть типа char или wchar_t.
Но в реальности _tcslen (и другие функции с префиксом _tcs) вовсе не функции, это макросы. Они просто описаны как:
Вы можете просмотреть заголовочный файл TCHAR.H и поискать там еще Макро описания похожее на вышеупомянутое.
Таким образом TCHAR оказывается вовсе не типом, а надстройкой над типами char и wchar_t. Позволяя тем самым выбирать мульти язычное приложение у нас будет или же все таки, одно язычное.
Вы спросите почему они описаны как макросы, а не как полноценная функция ??
Причина проста: Библиотека или DLL могут экспортировать простую функцию с тем же именем и прототипом (Исключая концепцию перегрузки в С++).
Для примера если вы экспортируете функцию:
Как должен вызывать ее клиент ?? Как:
_TPrintChar магическим образом может быть преобразована в функцию принимающая двух байтовый символ в качестве аргумента.
Для этого мы сделаем две различные функции:
И простой макрос скроет разницу между ними:
Клиент просто вызовет функцию как
Заметьте, что TCHAR и _TPrintChar теперь будут сопоставимы с UNICODE или ANSI, а переменная cChar и параметр функции будет сопоставим с типом данных char или wchar_t.
Макросы дают нам обойти эти сложности, и позволяют нам использовать ANSI или UNICODE функции для наших символов и строк. Множество функций Windows описаны именно таким образом, и для программиста есть только одна функция (то есть макрос) и это хорошо.
Приведу пример с SetWindowText:
Есть только несколько функций у которых нету таких макросов, и они только с суффиксом W или A. Пример тому функция ReadDirectoryChangesW, которая не имеет эквивалента в кодировки ANSI.
Как вы знаете, мы используем двойные кавычки для представления строк. Строка представленная в этой манере это ANSI-строка, на каждый символ используется 1 байт. Приведу пример:
Указанная верху строка не является строкой UNICODE, и не подходит для много языковой поддержки. Для того чтобы получить UNICODE строку вам надо использовать префикс L.
Приведу пример:
Поставьте спереди L и вы получите UNICODE строку. Все символы (Я повторяю все символы ) занимают 2 байта, включая Английские буквы, пробелы, цифры и символ null. Объем данных строки Unicode всегда будет кратен 2-м байтам. Строка Unicode длиной 7 символов будет занимать 14 байтов. Если строка Unicode занимает 15 байтов то это не правильная строка, и она не будет работать в любом контексте.
Также, строка будет кратна размеру sizeof(TCHAR) в байтах.
Когда Вам нужно жестко прописанный код, вы можете писать код так:
Строки без префикса это ANSI строки, с префиксом L строки Unicode, и строки с префиксом _T и TEXT зависимые от компиляции. И опять же _T и TEXT это снова макросы. Они определены так:
Символ ## это ключ(token) вставки оператора, который превратит _T(«Unicode») в L«Unicode», где строка это аргумент для макроса- если конечно _UNICODE определен.
Если _UNICODE не определен то _T(«Unicode») превратит это в «Unicode». Ключ вставки оператора существовал даже в языке С, и это не специфическая вещь связанная с кодировкой строк в VC++.
К сведению, макросы могут применятся не только для строк но и для символов. Например _T(‘R’) превратит это в L’R’ ну или в просто ‘R’. Тоесть либо в Unicode символ либо в ANSI символ.
Нет и еще раз нет, вы не можете использовать макрос чтобы конвертировать символ или строку в Unicode и не Unicode текст.
Следующий код будет неправильным:
Строки _T( c); _T(str); отлично скомпилируются в режиме ANSI, _T(x) превратится в x, и _T( c) вместе с _T(str) превратятся просто в c и str.
Но когда вы будете собирать проект в режиме Unicode код не с компилируется:
Я не хотел бы вызывать инсульт вашего интеллекта и объяснять почему это не работает.
Существует несколько функций для конвертирования Мульбайтовых строк в UNICODE, о которых я скоро расскажу.
Есть важное замечание, почти все функции которые принимает строку или символ, приоритетно в Windows API, имеют обобщенное название в MSDN и в других местах.
Функция SetWindowTextA/W будет классифицирована как:
Но как Вы знаете, SetWindowText это просто макрос, и в зависимости от настроек проекта будет рассматриваться как:
Так что не ломайте голову если не сможете получить адрес этой функции:
В библиотеке User32.DLL, имеются 2 функции SetWindowTextA и SetWindowTextW которые экспортируются, то есть тут нет имен с обобщенным названием.
Все функции которые имеют ANSI и UNICODE версию, вообще то имеют только UNICODE реализацию. Это значит, что когда Вы вызываете SetWindowTextA из своего кода, передавая параметр ANSI строку — она конвертирует ANSI в UNICODE вызывает SetWindowTextW.
Реальную работу (установку заголовка/названия/метки окна) делает только Unicode версия!
Возьмем другой пример, который будет получать текст окна, используя GetWindowText.
Вы вызываете GetWindowTextA передавая ему ANSI буфер как целевой буфер.
GetWindowTextA сначала вызовет GetWindowTextW, возможно выделяя память для Unicode строки (т.е массив wchar_t).
Затем он с конвертирует Unicode в ANSI строку для вас.
- CreateProcess
- GetUserName
- OpenDesktop
- DeleteFile
- итд
Поэтому очень рекомендуется вызывать напрямую Unicode функции.
В свою очередь, это означает, что вы всегда должны быть нацелены на сборку Unicode версии, а не на сборку ANSI версии, учитывая тот факт, что вы привыкли использовать ANSI строки в течение многих лет.
Да вы можете сохранять и получать ANSI строки, например для записи в файл, или отправки сообщения чата в ваше программе-чата. Функции конвертации существуют для таких нужд.
Замечание: Есть еще одно описание типа: имя ему WCHAR – оно эквивалентно wchar_t.
TCHAR это макрос, для декларирования одного символа. Вы также можете декларировать массив TCHAR. А что если Вы например захотите описать указатель на символы или, константный указатель на символы.
Приведу пример:
После чтения фишек с TCHAR, вы наверное предпочтете использовать именно его. Существуют еще хорошие альтернативы для представления строк в вашем коде. Для этого надо просто включить Windows.h в проект.
Примечание: Если ваш проект включает windows.h (косвенным или прямым образом), вы не должны включать в проект TCHAR.H.
Для начала пересмотрим старую функцию, чтобы было легче понять. Пример функцию strlen.
Которая может быть представлена по другому.
Где LPCSTR описан как:
LPCSTR понимается так.
• LP — Long Pointer (длинный указатель)
• C – Constant (константа)
• STR – String (строка)
По сути LPCSTR это (Длинный) указатель на строку.
Давайте изменим strcpy в соответствие с новым стилем имени типов:
szTarget имеет тип LPSTR, без использования типов языка С. LPSTR определен так:
Заметьте что szSource имеет тип LPCSTR, так как функция strcpy не модифицирует исходный буфер, поэтому выставлен атрибут const. Возвращаемый тип данных не константная строка: LPSTR.
Итак, функции с префиксом str для манипуляции с ANSI строками. Но нам нужна еще для двух байтовых Unicode строк. Для тех же больших символов имеются эквивалентные функции.
Для примера, чтобы посчитать длину символов больших символов(Unicode строки), вы будете использовать wcslen:
Прототип функции wcslen такой:
И код выше может быть представлен по другому:
Где LPCWSTR описан так:
LPCWSTR можно понять так:
LP — Long Pointer (Длинный указатель)
C — Constant (константа)
WSTR — Wide character String (строка больших символов)
Аналогичным образом, strcpy эквивалент wcscpy, для Unicode строк:
Который может быть представлен как:
Где szTarget это не константная большая строка (LPWSTR), а szSource константная большая строка.
Существует ряд эквивалентных wcs-функций для str-функций. str-функции будут использоваться для простых ANSI строк, а wcs-функции для Unicode строк.
Хотя Я уже советовал что надо использовать native Unicode функции, а не только ANSI или только синтезированные TCHAR функции. Причина проста — ваше приложение должно быть только Unicode-ным, и вы не должны заботится о том что спортируются ли они для ANSI. Но для полноты картины я и упомянул эти общие отображения (проецирования).
Чтобы вычислить длину строки, вы можете использовать _tcslen функцию (макро).
Который описан так:
Где имя типа LPCTSTR можно понять так
LP — Long Pointer (Длинный указатель)
C — Constant (Константа)
T = TCHAR
STR = String (Строка)
В зависимости от настроек проекта, LPCTSTR будет проецироваться в LPCSTR (ANSI) или в LPCWSTR (Unicode).
Заметьте: функции strlen, wcslen или _tcslen будут возвращать количество символов в строке, а не количество байтов.
Обобщенная операция копирования строки _tcscpy описана так:
Или в еще более обобщенной манере, как:
Вы можете догадаться что значит LPTSTR ))
Примеры использования.
Во первых приведу пример нерабочего кода:
На ANSI сборке, этот код успешно с компилируется потому что TCHAR будет типом char, и переменная name будет массивом char. Вызов strlen для name тоже будет прекрасно работать.
Итак. Давайте с компилируем тоже самое с включенными UNICODE/_UNICODE (в настройках проекта выберите «Use Unicode Character Set»).
Теперь компилятор будет выдавать такого рода ошибки:
И программисты начнут исправлять ошибку таким образом:
И это не усмирит компилятор, потому что конвертирование из TCHAR* в TCHAR[7] невозможно. Такая же ошибка будет возникать когда встроенные ANSI строки передаются Unicode функции:
К сожалению (или к счастью), эта ошибка может быть неправильно исправлена простым приведением типов языка C.
И вы думаете что повысили уровень своего опыта при работе с указателями. ВЫ не правы -этот код будет давать неправильный результат, и в большинстве вы будете получать Access Violation (нарушение доступа). Приведение типов таким образом это как передача float-переменной когда ожидалось(логически) структура размером 80 байт.
Строка «Saturn» это последовательность 7 байт:
| ‘S’ (83) | ‘a’ (97) | ‘t’ (116) | ‘u’ (117) | ‘r’ (114) | ‘n’ (110) | ‘\0’ (0) |
Но когда вы передаете тот же набор байтов в wcslen, он рассматривает каждые 2 байта как один символ. Поэтому первые 2 байта [97,83] будут рассматриваться как один символ имеющий значение 24915(97<<8 | 83). Это Unicode символ . И другие следующие символы рассматриваются как [117,116] и так далее.
Конечно вы не передавали эти Китайские символы, но приведение типов сделало это за Вас.
И поэтому очень важно знать что приведение типов не будет работать. Итак для инициализации первой строки вы должны сделать следующее:
Который будет транслировать в 7 или в 14 байт, в зависимости от компиляции.
Вызов wcslen должен быть таким:
В примере кода программы, приведенные выше, я использовал strlen, что вызывает ошибки при сборке Unicode.
Приведу пример нерабочего решение с приведением типов языка C:
На сборках Unicode переменная name будет размером 14 байт (7 unicode символов, включая null). Так как строка
«Saturn» содержит только Английские символы, которые можно представить используя ASCII кодирование, Unicode символ ‘S’ будет представлен как [83, 0]. Следующие ASCII символы будут представлены как нули. Заметьте сейчас символ ‘S’ представлен как 2-х байтовое значение 83. Конец строки будет представлен как 2 байта имеющее значение 0.
Итак, когда вы передаете такую строку в strlen, первый символ (то есть первый байт) будет правильным (‘S’ в случае с ‘Saturn’). Но следующий символ/байт будет идентифицирован как конец строки. Поэтому, strlen вернет неправильное значение 1.
Как Вы знаете, Unicode строка может содержать не только Английские символы, и результат strlen будет еще более неопределенным.
Короче говоря приведение типов не будет работать.
Вам придется, либо представлять строки в правильной форме, или использовать функции конвертирования ANSI в Unicode, и обратно.
Теперь, Я надеюсь Вы понимаете следующий код:
Продолжая тему. Вы наверное видели некоторые функции/методы которым нужно передавать количество символов, или возвращающие количество символов. Впрочем есть GetCurrentDirectory, в которую надо передавать число символов, а не количество байт.
Пример:
С другой стороны, если вам нужно выделять память для нужного количества символов, вы должны выделять надлежащее количество байт. В C + +, вы можете просто использовать оператор new:
Но если вы используете функции выделения памяти, такие как malloc, LocalAlloc, GlobalAlloc, и т.д., вы должны указывать количество байт!
Как вы знаете необходимо приведение типа возвращаемого значения. Выражение в аргументе malloc гарантирует, что оно выделяет необходимое количество байт — и выделяет места для нужного количества символов.
Wchar t c что это
Каждая переменная имеет определенный тип. И этот тип определяет, какие значения может иметь переменная, какие операции с ней можно производить и сколько байт в памяти она будет занимать. В языке C++ определены следующие базовые типы данных: логический тип bool , целочисленные типы, типа чисел с плавающей точкой, символьные типы. Рассмотрим эти группы по отдельности.
Логический тип
Логический тип bool может хранить одно из двух значений: true (истинно, верно) и false (неверно, ложно). Например, определим пару переменных данного типа и выведем их значения на консоль:
При выводе значения типа bool преобразуются в 1 (если true) и 0 (если false). Как правило, данный тип применяется преимущество в условных выражениях, которые будут далее рассмотрены.
Значение по умолчанию для переменных этого типа — false .
Целочисленные типы
Целые числа в языке C++ представлены следующими типами:
signed char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от -128 до 127
unsigned char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от 0 до 255
char : представляет один символ в кодировке ASCII. Занимает в памяти 1 байт (8 бит). Может хранить любое значение из диапазона от -128 до 127, либо от 0 до 255
Несмотря на то, что данный тип представляет тот же диапазон значений, что и вышеописанный тип signed char , но они не эквивалентны. Тип char предназначен для хранения числового кода символа и в реальности может представлять как signed byte , так и unsigned byte в зависимости от конкретного компилятора.
short : представляет целое число в диапазоне от –32768 до 32767. Занимает в памяти 2 байта (16 бит).
Данный тип также имеет псевдонимы short int , signed short int , signed short .
unsigned short : представляет целое число в диапазоне от 0 до 65535. Занимает в памяти 2 байта (16 бит).
Данный тип также имеет синоним unsigned short int .
int : представляет целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита). Диапазон предельных значений соответственно также может варьироваться от –32768 до 32767 (при 2 байтах) или от −2 147 483 648 до 2 147 483 647 (при 4 байтах). Но в любом случае размер должен быть больше или равен размеру типа short и меньше или равен размеру типа long
Данный тип имеет псевдонимы signed int и signed .
unsigned int : представляет положительное целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита), и из-за этого диапазон предельных значений может меняться: от 0 до 65535 (для 2 байт), либо от 0 до 4 294 967 295 (для 4 байт).
Имеет псевдоним unsigned
long : в зависимости от архитектуры может занимать 4 или 8 байт и представляет целое число в диапазоне от −2 147 483 648 до 2 147 483 647 (при 4 байтах) или от −9 223 372 036 854 775 808 до +9 223 372 036 854 775 807 (при 8 байтах). Занимает в памяти 4 байта (32 бита) или.
Имеет псевдонимы long int , signed long int и signed long
unsigned long : представляет целое число в диапазоне от 0 до 4 294 967 295. Занимает в памяти 4 байта (32 бита).
Имеет синоним unsigned long int .
long long : представляет целое число в диапазоне от −9 223 372 036 854 775 808 до +9 223 372 036 854 775 807. Занимает в памяти 8 байт (64 бита).
Имеет псевдонимы long long int , signed long long int и signed long long .
unsigned long long : представляет целое число в диапазоне от 0 до 18 446 744 073 709 551 615. Занимает в памяти, как правило, 8 байт (64 бита).
Имеет псевдоним unsigned long long int .
Для представления чисел в С++ применятся целочисленные литералы со знаком или без, типа -10 или 10. Например, определим ряд переменных целочисленных типов и выведем их значения на консоль:
Различные системы исчисления
По умолчанию все стандартные целочисленные литералы представляют числа в привычной нам десятичной системе. Однако C++ также позволяет использовать и числа в других системах исчисления.
Чтобы указать, что число — шестнадцатеричное, перед числом указывается префикс 0x или 0X . Например:
Чтобы указать, что число — восьмеричное, перед числом указывается ноль 0 . Например:
Бинарные литералы предваряются префиксом 0b или 0B :
Все эти типы литералов также поддерживают суффиксы U/L/LL :
Числа с плавающей точкой
Для хранения дробных чисел в C++ применяются числа с плавающей точкой. Число с плавающей точкой состоит из двух частей: мантиссы и показателя степени . Оба могут быть как положительными, так и отрицательными. Величина числа – это мантисса, умноженная на десять в степени экспоненты.
Например, число 365 может быть записано в виде числа с плавающей точкой следующим образом:
В качестве разделителя целой и дробной частей используется символ точки. Мантисса здесь имеет семь десятичных цифр — 3.650000 , показатель степени — две цифры 02 . Буква E означает экспоненту, после нее указывается показатель степени (степени десяти), на которую умножается часть 3.650000 (мантисса), чтобы получить требуемое значение. То есть, чтобы вернуться к обычному десятичному представлению, нужно выполнить следующую операцию:
Другой пример — возьмем небольшое число:
В данном случае мы имеем дело с числом –3.65 × 10 -3 , что равно –0.00365 . Здесь мы видим, что в зависимости от значения показателя степени десятичная точка «плавает». Собственно поэтому их и называют числами с плавающей точкой.
Однако хотя такая запись позволяет определить очень большой диапазон чисел, не все эти числа могут быть представлены с полной точностью; числа с плавающей запятой в целом являются приблизительными представления точного числа. Например, число 1254311179 выглядело бы так: 1.254311E09 . Однако если перейти к десятичной записи, то это будет 1254311000 . А это не то же самое, что и 1254311179 , поскольку мы потеряли три младших разряда.
В языке C++ есть три типа для представления чисел с плавающей точкой:
float : представляет вещественное число одинарной точности с плавающей точкой в диапазоне +/- 3.4E-38 до 3.4E+38. В памяти занимает 4 байта (32 бита)
double : представляет вещественное число двойной точности с плавающей точкой в диапазоне +/- 1.7E-308 до 1.7E+308. В памяти занимает 8 байт (64 бита)
long double : представляет вещественное число двойной точности с плавающей точкой не менее 8 байт (64 бит). В зависимости от размера занимаемой памяти может отличаться диапазон допустимых значений.
В своем внутреннем бинарном представлении каждое число с плавающей запятой состоит из одного бита знака, за которым следует фиксированное количество битов для показателя степени и набор битов для хранения мантиссы. В числах float 1 бит предназначен для хранения знака, 8 бит для экспоненты и 23 для мантиссы, что в сумме дает 32 бита. Мантисса позволяет определить точность числа в виде 7 десятичных знаков.
В числах double : 1 знаковый бит, 11 бит для экспоненты и 52 бит для мантиссы, то есть в сумме 64 бита. 52-разрядная мантисса позволяет определить точность до 16 десятичных знаков.
Для типа long double расклад зависит от конкретного компилятора и реализации этого типа данных. Большинство компиляторов предоставляют точность до 18 — 19 десятичных знаков (64-битная мантисса), в других же (как например, в Microsoft Visual C++) long double аналогичен типу double .
В C++ литералы чисел с плавающими точками представлены дробными числами, которые в качестве разделителя целой и дробной частей применяют точку:
Даже если переменной присваивается целое число, чтобы показать, что мы присваиваем число с плавающей точкой, применяется точка:
Так, здесь число 1. представляет литерал числа с плавающей точкой, и в принципе аналогичен 1.0 .
По умолчанию все такие числа с точкой расцениваются как числа типа double. Чтобы показать, что число представляет другой тип, для float применяется суффикс f / F , а для long double — l / L :
В качестве альтернативы также можно применять экспоненциальную запись:
Размеры типов данных
При перечислении типов данных указывался размер, который он занимает в памяти. Но стандарт языка устанавливает лишь минимальные значения, которые должны быть. Например, для типов int и short минимальное значение — 16 бит, для типа long — 32 бита, для типа long double — 64 разряда. При этом размер типа long должен быть не меньше размера типа int, а размер типа int — не меньше размера типа short, а размер типа long double должен быть не меньше double . А разработчики компиляторов могут выбирать предельные размеры для типов самостоятельно, исходя из аппаратных возможностей компьютера.
К примеру, компилятор g++ Windows для long double использует 16 байт. А компилятор в Visual Studio, который также работает под Windows, и clang++ под Windows для long double используют 8 байт. То есть даже в рамках одной платформы разные компиляторы могут по разному подходить к размерам некоторых типов данных. Но в целом используются те размеры, которые указаны выше при описании типов данных.
Однако бывают ситуации, когда необходимо точно знать размер определенного типа. И для этого в С++ есть оператор sizeof() , который возвращает размер памяти в байтах, которую занимает переменная:
Символьные типы
В C++ есть следующие символьные типы данных:
char : представляет один символ в кодировке ASCII. Занимает в памяти 1 байт (8 бит). Может хранить любое значение из диапазона от -128 до 127, либо от 0 до 255
wchar_t : представляет расширенный символ. На Windows занимает в памяти 2 байта (16 бит), на Linux — 4 байта (32 бита). Может хранить любой значение из диапазона от 0 до 65 535 (при 2 байтах), либо от 0 до 4 294 967 295 (для 4 байт)
char8_t : представляет один символ в кодировке Unicode. Занимает в памяти 1 байт. Может хранить любой значение из диапазона от 0 до 256
char16_t : представляет один символ в кодировке Unicode. Занимает в памяти 2 байта (16 бит). Может хранить любой значение из диапазона от 0 до 65 535
char32_t : представляет один символ в кодировке Unicode. Занимает в памяти 4 байта (32 бита). Может хранить любой значение из диапазона от 0 до 4 294 967 295
Переменная типа char хранит числовой код одного символа и занимает один байт. Стандарт языка С++ не определяет кодировку символов, которая будет использоваться для символов char, поэтому производители компиляторов могут выбирать любую кодировку, но обычно это ASCII.
В качестве значения переменная типа char может принимать один символ в одинарных кавычках, либо числовой код символа:
В данном случае переменные a1 и a2 будут иметь одно и то же значение, так как 65 — это числовой код символа «A» в таблице ASCII. При выводе на консоль с помощью cout по умолчанию отображается символ.
Кроме того, в C++ можно использовать специальные управляющие последовательности, которые предваряются слешем и которые интерпретируются особым образом. Например, «\n» представляет перевод строки, а «\t» — табуляцию.
Однако ASCII обычно подходит для наборов символов языков, которые используют латиницу. Но если необходимо работать с символами для нескольких языков одновременно или с символами языков, отличных от английского, 256-символьных кодов может быть недостаточно. И в этом случае применяется Unicode .
Unicode (Юникод) — это стандарт, который определяет набор символов и их кодовых точек, а также несколько различных кодировок для этих кодовых точек. Наиболее часто используемые кодировки: UTF-8, UTF-16 и UTF-32. Разница между ними заключается в том, как представлена кодовая точка символа; числовое же значение кода для любого символа остается одним и тем же в любой из кодировок. Основные отличия:
UTF-8 представляет символ как последовательность переменной длины от одного до четырех байт. Набор символов ASCII появляется в UTF-8 как однобайтовые коды, которые имеют те же значения кодов, что и в ASCII. UTF-8 на сегодняшний день является самой популярной кодировкой Unicode.
UTF-16 представляет символы как одно или два 16-битных значения.
UTF-32 представляет все символы как 32-битные значения
В C++ есть четыре типа для хранения символов Unicode: wchar_t , char8_t , char16_t и char32_t ( char16_t и char32_t были добавлены в C+11, а char8_t — в C++20).
wchar_t
Тип wchar_t — это основной тип, предназначенный для наборов символов, размер которых выходит за пределы одного байта. Собственно отсюда и его название: wchar_t — wide (широкий) char. происходит от широкого символа, потому что этот символ «шире», чем обычный однобайтовый символ. Значения wchar_t определяются также как и символы char за тем исключением, что они предваряются символов «L»:
Также можно передать код символа
Значение, заключенное в одинарные кавычки, представляет собой шестнадцатеричный код символа. Обратная косая черта указывает на начало управляющей последовательности, а x после обратной косой черты означает, что код шестнадцатеричный.
Стоит учитывать, что для вывода на консоль символов wchar_t следует использовать не std::cout , а поток std::wcout :
При этом поток std::wcout может работать как с char, так и с wchar_t. А поток std::cout для переменной wchar_t вместо символа будет выводить его числовой код.
Проблема с типом wchar_t заключается в том, что его размер сильно зависит от реализации и применяемой кодировки. Кодировка обычно соответствует предпочтительной кодировке целевой платформы. Так, для Windows wchar_t обычно имеет ширину 16 бит и кодируется с помощью UTF-16. Большинство других платформ устанавливают размер в 32 бита, а в качестве кодировки применяют UTF-32. С одной стороны, это позволяет больше соответствовать конкретной платформе. Но с другой стороны, затрудняет написание кода, переносимого на разные платформы. Поэтому в общем случае часто рекомендуется использовать типы char8_t , char16_t и char32_t . Значения этих типов предназначены для хранения символов в кодировке UTF-8, UTF-16 или UTF-32 соответственно, а их размеры одинаковы на всех распространенных платформах.
Для определения символов типов char8_t , char16_t и char32_t применяются соответственно префиксы u8, u и U:
Стоит отметить, что для вывода на консоль значений char8_t/char16_t/char32_t пока нет встроенных инструментов типа std:cout/std:wcout .
Спецификатор auto
Иногда бывает трудно определить тип выражения. В этом случае можно предоставить компилятору самому выводить тип объекта. И для этого применяется спецификатор auto . При этом если мы определяем переменную со спецификатором auto, эта переменная должна быть обязательно инициализирована каким-либо значением:
На основании присвоенного значения компилятор выведет тип переменной. Неинициализированные переменные со спецификатором auto не допускаются:
Name already in use
cpp-docs / docs / cpp / fundamental-types-cpp.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
32 contributors
Users who have contributed to this file
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Built-in types (C++)
Built-in types (also called fundamental types) are specified by the C++ language standard and are built into the compiler. Built-in types aren’t defined in any header file. Built-in types are divided into three main categories: integral, floating-point, and void. Integral types represent whole numbers. Floating-point types can specify values that may have fractional parts. Most built-in types are treated as distinct types by the compiler. However, some types are synonyms, or treated as equivalent types by the compiler.
The void type describes an empty set of values. No variable of type void can be specified. The void type is used primarily to declare functions that return no values or to declare generic pointers to untyped or arbitrarily typed data. Any expression can be explicitly converted or cast to type void . However, such expressions are restricted to the following uses:
An expression statement. (For more information, see Expressions.)
The left operand of the comma operator. (For more information, see Comma Operator.)
The second or third operand of the conditional operator ( ? : ). (For more information, see Expressions with the Conditional Operator.)
The keyword nullptr is a null-pointer constant of type std::nullptr_t , which is convertible to any raw pointer type. For more information, see nullptr .
The bool type can have values true and false . The size of the bool type is implementation-specific. See Sizes of built-in types for Microsoft-specific implementation details.
The char type is a character representation type that efficiently encodes members of the basic execution character set. The C++ compiler treats variables of type char , signed char , and unsigned char as having different types.
Microsoft-specific: Variables of type char are promoted to int as if from type signed char by default, unless the /J compilation option is used. In this case, they’re treated as type unsigned char and are promoted to int without sign extension.
A variable of type wchar_t is a wide-character or multibyte character type. Use the L prefix before a character or string literal to specify the wide-character type.
Microsoft-specific: By default, wchar_t is a native type, but you can use /Zc:wchar_t- to make wchar_t a typedef for unsigned short . The __wchar_t type is a Microsoft-specific synonym for the native wchar_t type.
The char8_t type is used for UTF-8 character representation. It has the same representation as unsigned char , but is treated as a distinct type by the compiler. The char8_t type is new in C++20. Microsoft-specific: use of char8_t requires the /std:c++20 compiler option or later (such as /std:c++latest ).
The char16_t type is used for UTF-16 character representation. It must be large enough to represent any UTF-16 code unit. It’s treated as a distinct type by the compiler.
The char32_t type is used for UTF-32 character representation. It must be large enough to represent any UTF-32 code unit. It’s treated as a distinct type by the compiler.
Floating-point types use an IEEE-754 representation to provide an approximation of fractional values over a wide range of magnitudes. The following table lists the floating-point types in C++ and the comparative restrictions on floating-point type sizes. These restrictions are mandated by the C++ standard and are independent of the Microsoft implementation. The absolute size of built-in floating-point types isn’t specified in the standard.
| Type | Contents |
|---|---|
| float | Type float is the smallest floating point type in C++. |
| double | Type double is a floating point type that is larger than or equal to type float , but shorter than or equal to the size of type long double . |
| long double | Type long double is a floating point type that is larger than or equal to type double . |
Microsoft-specific: The representation of long double and double is identical. However, long double and double are treated as distinct types by the compiler. The Microsoft C++ compiler uses the 4- and 8-byte IEEE-754 floating-point representations. For more information, see IEEE floating-point representation.
The int type is the default basic integer type. It can represent all of the whole numbers over an implementation-specific range.
A signed integer representation is one that can hold both positive and negative values. It’s used by default, or when the signed modifier keyword is present. The unsigned modifier keyword specifies an unsigned representation that can only hold non-negative values.
A size modifier specifies the width in bits of the integer representation used. The language supports short , long , and long long modifiers. A short type must be at least 16 bits wide. A long type must be at least 32 bits wide. A long long type must be at least 64 bits wide. The standard specifies a size relationship between the integral types:
1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
An implementation must maintain both the minimum size requirements and the size relationship for each type. However, the actual sizes can and do vary between implementations. See Sizes of built-in types for Microsoft-specific implementation details.
The int keyword may be omitted when signed , unsigned , or size modifiers are specified. The modifiers and int type, if present, may appear in any order. For example, short unsigned and unsigned int short refer to the same type.
Integer type synonyms
The following groups of types are considered synonyms by the compiler:
short , short int , signed short , signed short int
unsigned short , unsigned short int
int , signed , signed int
unsigned , unsigned int
long , long int , signed long , signed long int
unsigned long , unsigned long int
long long , long long int , signed long long , signed long long int
unsigned long long , unsigned long long int
Microsoft-specific integer types include the specific-width __int8 , __int16 , __int32 , and __int64 types. These types may use the signed and unsigned modifiers. The __int8 data type is synonymous with type char , __int16 is synonymous with type short , __int32 is synonymous with type int , and __int64 is synonymous with type long long .
Sizes of built-in types
Most built-in types have implementation-defined sizes. The following table lists the amount of storage required for built-in types in Microsoft C++. In particular, long is 4 bytes even on 64-bit operating systems.