断言值文本没有类型是假的

Assert that the value literals have no type is false?

本文关键字:类型 文本 断言      更新时间:2023-10-16

我在主题、文章和 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 * constconst 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];

声明和数组charx

事实上,C 预处理器可用于 C 以外的语言的源文件。例如,它通常用于FORTRAN源。由于 FORTRAN 没有标准的预处理器。

为什么常识是文字值(和 #defines)没有类型,但可以用文字指定类型? 换句话说: 断言值文字没有类型是假的?

不是。文本都有类型,如 C++11 标准的第 2.14 节所述。在解释文本之前替换预处理器宏。

没有后缀和小数(如 100)的值文字,总是可以被认为是 int 类型吗?

不;十进制文本是intlong intlong 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] .