断言值文本没有类型是假的
Assert that the value literals have no type is false?
我在主题、文章和 SO 答案中读到#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
cualifier,它是一个 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
)没有类型,但可以用文字指定类型? 换句话说:断言文本没有类型的值是假的? - 没有后缀和小数的值文字(如
100
),总是可以被认为是 int 类型吗? - 即使考虑其前缀,文本文字的类型和限定符是什么?
在 C 和 C++ 中,预处理器和编译器是两个独立的实体。
处理 #define
和其他预处理器指令的预处理器没有类型系统。它操作字符串。无论这些字符表示什么值,都留给编译器本身。
考虑
#define Y x[
这是一个合法的预处理器指令,即使字符串 x[
在 C 中没有任何意义。然而,您可以将其用作
char Y 10];
声明和数组char
的x
。
事实上,C 预处理器可用于 C 以外的语言的源文件。例如,它通常用于FORTRAN源。由于 FORTRAN 没有标准的预处理器。
为什么常识是文字值(和 #defines)没有类型,但可以用文字指定类型? 换句话说: 断言值文字没有类型是假的?
不是。文本都有类型,如 C++11 标准的第 2.14 节所述。在解释文本之前替换预处理器宏。
没有后缀和小数(如 100)的值文字,总是可以被认为是 int 类型吗?
不;十进制文本是int
、long int
或long long int
中的第一个,可以表示该值。如有必要,八进制或十六进制文本也可以是无符号的。在 2011 年之前,long long
不被考虑,因为它不是标准类型。
因此,100
将具有int
类型,因为它足够小,可以用int
表示。
即使考虑其前缀,文本文字的类型和限定符是什么?
没有前缀,它是一个const char
数组,大到足以容纳所有字符和零终止符。所以"Text"
有类型 char const[5]
.
使用前缀时,字符类型将更改为您在问题中给出的类型;数组大小仍然足够大,可以容纳包括终止符在内的所有字符。
首先,您的问题:
断言文本没有类型的值是假的?
是的。
没有后缀和小数(如 100)的值文字,总是可以被认为是 int 类型吗?
我认为默认情况下,您会得到类型 int
.
即使考虑其前缀,文本文字的类型和修饰符是什么?
如果我没记错的话,默认类型是 char []
.
第二,一些背景:
值文本有一个类型 - 只是它没有显式指定,并非所有类型都可以这样指定。
通过声明常量,可以显式指定类型,并为编译器提供更多信息。
考虑一下:
#define VALUE1 102
会告诉你你的值是一个整数字面。
通过声明一个 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
。您可以使用预处理器将该文本插入字符串文本的中间 - 例如,this。
宏没有类型。预处理器可以创建编译器随后可以解释为具有类型的标记 - 但这是切线的,它不必做任何这样的事情。
此外,L""
文字是 C++03 和 wchar_t
.文字""
的类型为 const char[1]
,并且是左值。它们是左值的原因是,传统上,它们是用const char*
指向的,并且该指针必须指向一个左值,否则它将在有用之前变得无效,而传统的 C 数组不能是右值。
#define
告诉预编译器将所有实例替换为定义,因此类型在变量中不是显式的,但可以通过查看它所表示的文本值来确定。
- 整数文字是没有任何修饰符的
int
,或者可以制成long
等,如 436234636L。
字符串 - 文字是普通字符串,除非像您的问题中那样附加修饰符。
#define
是预处理器的指令,预处理器只执行复制和粘贴样式替换。 预处理器不知道也不关心代码的含义,也没有类型的概念。
预处理后,编译器将处理表达式、语句、类型等。 每个表达式(除非它是重载函数的名称或地址)都有一个类型,该类型仅依赖于该表达式,而不依赖于代码的上下文。
(C++11 的大括号初始化列表没有类型,并且在技术上不是表达式,尽管它们可以出现在许多相同的上下文中。
所以#define VALUE 100
对预处理器有意义,但在这一点上,类型的概念甚至不适用。 但是之后几乎任何正确使用VALUE
都会将其用作表达式,并且这些表达式都将具有类型 int
。
是的,数字后缀和字符串前缀确实会影响文本表达式的类型。 100
的类型是int
,但100UL
的类型是unsigned long
。
文字"Text"
始终具有类型 const char [5]
,但char
的确切含义和表示形式可能取决于您的编译器。 在大多数情况下,该文本将使用隐式数组到指针的转换立即衰减到 const char*
类型。 (此外,为了向后兼容const
发明之前的古代 C 代码,C++允许从字符串文字初始化 char*
变量,但最好不要让这种情况发生。
类似地,文本L"Text"
具有类型 const wchar_t [5]
,依此类推。
当预处理器看到文本#define VALUE 100
时,它将字符串存储VALUE
[或类似的东西],并将"替换"存储为100。每当预处理器后来找到VALUE
时,它就会用100
替换它。因此,VALUE
没有类型。C语言中的文本100
确实有一个类型 - 它是一个int
,因为这就是语言规则所说的。
发生在正确编译之前,因此预处理器替换可以做各种"奇怪"的事情,如果没有宏很难(有时是不可能的)。
同样,预处理器只是将TEXT
替换为"Text"
,此时它没有类型。类型仅存在于正确的编译器中。因此,如果您有:
#define TEXT "Text"
void myfun(int x)
{
...
}
...
myfun(TEXT);
预处理器将产生
...
myfun("Text");
只有当你正确编译代码时,编译器才会发现"嗯,这是一个文本字符串,它不是预期的整数",并给你某种错误。
至于"Text"
的"类型",它确实取决于确切的上下文。在大多数情况下,安全的做法是将其视为 const char *
,但在某些情况下,也可以认为 char [5]
.
- CRTP 单一实例不完整类型或非文本类型
- 如何从文本文件中读取数值,直到遇到字符类型?
- 如何将文本文件的特定行读取到 int 类型的数组中C++?
- 文本冒险游戏 - 如何区分一种项目类型与另一种项目类型以及如何构建项目类/子类
- 是否可以创建一个用户定义的文本,将字符串文本转换为 own 类型的数组?
- 如何使用C++将.trc文件类型转换为文本文件?
- 整数文本太大,无法用任何整数类型表示--C++
- 具有引用数据成员的结构不是文本类型吗?
- 指针类型是文本类型吗?
- FindResource 调用返回 RCDATA 类型的文本文件的 NULL
- 文本类类型成员函数约束
- 当浮点数文本直接分配给不同的类型时,编译器如何处理浮点文字?
- 如何在自由类型中获取文本宽度
- 常量表达式中的非文本类型'compare'
- C++文本整数类型
- 运行时文本类型的惊人行为
- 在C 中按行读取文本文件,每行都是不同的数据类型
- 设计具有变体字段的文本类型类,其中可以存储一个或三个对象
- (视觉-)C++ 字符串文本的模板类型推断 - VS 2010 与 VS 2017
- QString:包括非文本类型的静态数据成员的初始化