Утверждать, что значения литералов не имеют типа — ложь?

Я читал в темах, статьях и ТАК ответы, что #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

Подумав обо всем этом, я немного растерялся, поэтому прошу совета:

  • Почему общеизвестно, что буквальные ценности (и #defines) не имеют типа, но тип можно указать с помощью литерала? другими словами: утверждать, что литералы значения не имеют типа — ложь?
  • Значение литерала без суффикса и без десятичных знаков (как 100), всегда можно считать типом int?
  • Какой тип и классификаторы текстовых литералов, даже с учетом его префиксов?

0

Решение

Почему общеизвестно, что литеральные значения (и #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],

С префиксами тип символа меняется на типы, которые вы задаете в вопросе; размер массива все еще достаточно велик для всех символов, включая терминатор.

2

Другие решения

В C и C ++ препроцессор и компилятор являются двумя отдельными объектами.

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

Рассматривать

#define Y x[

Это легальная директива препроцессора, даже если строка x[ не имеет никакого смысла в C. Тем не менее, вы можете использовать его как

char Y 10];

объявить и массив x из char,

Фактически препроцессор C может использоваться в исходных файлах для языков, отличных от C. Например, он часто используется для источников на языке FORTRAN. Поскольку ФОРТРАН не имеет стандартного препроцессора.

4

Сначала ваши вопросы:

Утверждать, что значения литералов не имеют типа — ложь?

Да.

Значение литерала без суффикса и без десятичных знаков (например, 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 ...

На этом этапе вам лучше добавлять константы.

2

Они верны в том, что у препроцессора нет типов. Ваш пример

#define VALUE_L   100l

Это не значит что VALUE_L имеет тип long, Вы можете использовать препроцессор, чтобы вставить этот текст в середину строкового литерала — например, этот.

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

Также, L"" литералы C ++ 03 и wchar_t, Буквальный "" имеет тип const char[1]и является lvalue. Причина, по которой они являются lvalues, заключается в том, что традиционно на них указывают const char*и этот указатель должен указывать на lvalue, иначе он станет недействительным, прежде чем станет полезным, и традиционные массивы C не могут быть значениями.

2

#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], и так далее.

1

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

  • Целочисленный литерал является int без каких-либо модификаторов, или же может быть превращен в long и т.д., как 436234636L.
  • Строковый литерал — это обычная строка, если к ней не добавлены модификаторы, как в вашем вопросе.
0

Когда препроцессор видит текст #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],

0
По вопросам рекламы [email protected]