Я читал в темах, статьях и ТАК ответы, что #define
значения не имеют типа, я решил обдумать эту концепцию, думая, что тип — это свойство переменной контейнера, а не свойство самого значения:
const char cVALUE = 100; // 'cVALUE' is char with value 100, wich type is '100'?
const short sVALUE = 100; // 'sVALUE' is short with value 100, wich type is '100'?
const int iVALUE = 100; // 'iVALUE' is int with value 100, wich type is '100'?
#define VALUE 100 // wich type is 'VALUE'?
Но как насчет суффиксы значений?
#define VALUE_L 100l // 'VALUE_L' is long?
#define VALUE_UL 100ul // 'VALUE_UL' is unsigned long?
#define VALUE_LL 100ll // 'VALUE_LL' is long long?
#define VALUE_ULL 100ull // 'VALUE_ULL' is unsigned long long?
В приведенном выше коде тип, кажется, привязан к значению, поэтому все эти необработанные значения являются типизированными значениями, в отличие от того, что я читал ранее. Но это еще не все! текстовые литералы даже имеют классификаторы, например:
#define TEXT "Text" // '"Text"' is an array of some kind of chars.
Текстовое значение в #define
выше есть тип (тип символа, если вы работаете с MSVC, я думаю, что тип символа может меняться в зависимости от настройки проекта -> Набор символов, не знаю, если это возможно в других IDE) он также имеет const
Классификатор и это LValue вместо RValue, все эти различия в поведении между числовыми и текстовыми литералами меня беспокоят.
Итак, предполагая, что тип символа char
тип литерала "Text"
является const char *
, const char * const
или же const char[5]
? или, по крайней мере, он не имеет типа вообще, прежде чем правильный контекст будет выведен на контекст?
И в стандарте C ++ 11 текстовые литералы также могут иметь тип, используя некоторые префиксы который устанавливает кодировку:
#define TEXT L"Text" // wide string with char type wchar_t
#define TEXTu8 u8"Text" // UTF-8 string with char type char
#define TEXTu u"Text" // UTF-16 string with char type char16_t
#define TEXTU U"Text" // UTF-32 string with char type char32_t
Подумав обо всем этом, я немного растерялся, поэтому прошу совета:
#define
s) не имеют типа, но тип можно указать с помощью литерала? другими словами: утверждать, что литералы значения не имеют типа — ложь?100
), всегда можно считать типом int?Почему общеизвестно, что литеральные значения (и #defines) не имеют типа, но тип можно указать с помощью литерала? другими словами: утверждать, что литералы значения не имеют типа — ложь?
Это не. Все литералы имеют типы, как указано в разделе 2.14 стандарта C ++ 11. Макросы препроцессора заменяются до интерпретации литералов.
Значение литерала без суффикса и без десятичных знаков (например, 100) всегда можно рассматривать как тип int?
Нет; десятичный литерал является первым из int
, long int
или же long long int
это может представлять ценность. Восьмеричные или шестнадцатеричные литералы также могут быть без знака при необходимости. До 2011 года long long
не рассматривался, так как это не был стандартный тип.
Так 100
будет иметь тип int
так как он достаточно мал, чтобы быть представленным int
,
Какой тип и классификаторы текстовых литералов, даже с учетом его префиксов?
Без префикса это массив const char
, достаточно большой, чтобы вместить все символы и нулевой терминатор. Так "Text"
имеет тип char const[5]
,
С префиксами тип символа меняется на типы, которые вы задаете в вопросе; размер массива все еще достаточно велик для всех символов, включая терминатор.
В C и C ++ препроцессор и компилятор являются двумя отдельными объектами.
Препроцессор, который обрабатывает #define
s и другие директивы препроцессора не имеют системы типов. Он манипулирует строками персонажей. И все значения, которые представляют эти символы, оставляются на усмотрение самого компилятора.
Рассматривать
#define Y x[
Это легальная директива препроцессора, даже если строка x[
не имеет никакого смысла в C. Тем не менее, вы можете использовать его как
char Y 10];
объявить и массив x
из char
,
Фактически препроцессор C может использоваться в исходных файлах для языков, отличных от C. Например, он часто используется для источников на языке FORTRAN. Поскольку ФОРТРАН не имеет стандартного препроцессора.
Сначала ваши вопросы:
Утверждать, что значения литералов не имеют типа — ложь?
Да.
Значение литерала без суффикса и без десятичных знаков (например, 100) всегда можно рассматривать как тип int?
Я думаю, что по умолчанию вы получаете тип int
,
Каков тип и классификаторы текстовых литералов, даже учитывая его префиксы?
Если я правильно помню, тип по умолчанию char []
,
Во-вторых, некоторый контекст:
Значение литералов иметь тип — просто он не указан явно, и не все типы могут быть указаны таким образом.
Объявляя константу, вы можете явно указать тип и дать компилятору гораздо больше информации.
Считают, что:
#define VALUE1 102
скажет вам, что ваша ценность является литералом int.
Объявляя const, вы можете сказать:
static const int VALUE1 = 102;
static const float VALUE1 = 102;
static const double VALUE1 = 102;
static const unsigned int VALUE1 = 102;
Правильный / лучший способ сделать define
(правильно относительный термин для использования define
для констант) будет:
#define VALUE1 (int(102))
#define VALUE1 (float(102))
// etc ...
На этом этапе вам лучше добавлять константы.
Они верны в том, что у препроцессора нет типов. Ваш пример
#define VALUE_L 100l
Это не значит что VALUE_L
имеет тип long
, Вы можете использовать препроцессор, чтобы вставить этот текст в середину строкового литерала — например, этот.
Макрос не имеет типа. Препроцессор может создавать токены, которые компилятор может затем интерпретировать как имеющий тип, но это касательно и ему не нужно делать ничего подобного.
Также, L""
литералы C ++ 03 и wchar_t
, Буквальный ""
имеет тип const char[1]
и является lvalue. Причина, по которой они являются lvalues, заключается в том, что традиционно на них указывают const char*
и этот указатель должен указывать на lvalue, иначе он станет недействительным, прежде чем станет полезным, и традиционные массивы C не могут быть значениями.
#define
является директивой препроцессору, который просто выполняет замены стиля копирования и вставки. Препроцессор не знает и не заботится о том, что означает код, и не имеет понятия о типах.
После предварительной обработки компилятор обрабатывает выражения, операторы, типы и т. Д. Каждое выражение (если это не имя или адрес перегруженной функции) имеет тип, который зависит только от этого выражения, а не от контекста кода.
(C ++ 11-х рамно-Init-листы не имеют типов и не являются технически выражениями, хотя могут встречаться во многих одинаковых контекстах.)
Так #define VALUE 100
имеет значение для препроцессора, но в этот момент идея типа даже не применима. Но почти любое правильное использование VALUE
после этого будет использовать его как выражение, и все эти выражения будут иметь тип int
,
Да, числовые суффиксы и строковые префиксы действительно влияют на тип литерального выражения. Тип 100
является int
, но тип 100UL
является unsigned long
,
Буквальный "Text"
всегда имеет тип const char [5]
, но точное значение и представление char
может зависеть от вашего компилятора. В большинстве случаев этот литерал мгновенно затухает, используя неявное преобразование массива в указатель, в const char*
тип. (Кроме того, для обратной совместимости с древним кодом C до изобретения const
, C ++ позволяет инициализировать char*
переменная из строкового литерала, но лучше этого не допустить.)
Точно так же буквальный L"Text"
имеет тип const wchar_t [5]
, и так далее.
#define
говорит прекомпилятору заменить все экземпляры определением, чтобы тип не был явным в переменной, но его можно определить, посмотрев на буквальное значение, которое он представляет.
int
без каких-либо модификаторов, или же может быть превращен в long
и т.д., как 436234636L.Когда препроцессор видит текст #define VALUE 100
хранит строку VALUE
[или что-то подобное], и «замена» как 100. Всякий раз, когда препроцессор позже находит VALUE
, он заменяет его 100
, В качестве таких, VALUE
не имеет типа. Текст 100
в Си есть тип — это int
потому что так говорят правила языков.
Имейте в виду, что замена препроцессора происходит до правильной компиляции, поэтому замена препроцессора может делать всевозможные «странные» вещи, которые трудно (или иногда невозможно) сделать без макросов.
Опять препроцессор просто заменили TEXT
с "Text"
и в этот момент он не имеет типа. Типы существуют только в правильном компиляторе. Так что если у вас есть:
#define TEXT "Text"
void myfun(int x)
{
...
}
...
myfun(TEXT);
препроцессор будет производить
...
myfun("Text");
Только когда вы доберетесь до правильной компиляции кода, компилятор обнаружит, что «Хм, это текстовая строка, а не целое число, как ожидалось», и выдаст вам какую-то ошибку.
Что касается «типа» "Text"
, это зависит от точного контекста. В большинстве случаев безопаснее всего рассматривать его как const char *
, но в некоторых контекстах это также может быть рассмотрено char [5]
,