我已经阅读了#define
值没有类型的主题,文章和SO答案,我已经围绕这个概念做出了决定,认为类型是容器变量的属性,而不是价值本身的属性:
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'?
但是,value suffixes呢?
#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我认为字符类型可能会因project settings -> Character set而变化,不知道是否可能在另一个IDE)它也有const
cualifier,它是一个LValue而不是RValue,数字和文本文字之间的所有这些行为差异都会让我感到不安。
因此,假设字符类型为char
,文字"Text"
的类型为const char *
,const char * const
或const char[5]
?或者至少,在上下文推断出正确的类型之前它根本没有类型?
而且,在C ++ 11标准中,文本文字也可以使用一些设置字符集的prefixes类型:
#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类型?答案 0 :(得分:4)
在C和C ++中,预处理器和编译器是两个独立的实体。
处理#define
和其他预处理程序指令的预处理程序没有类型系统。它操纵字符串。这些字符代表的任何值留给编译器本身。
考虑
#define Y x[
这是一个合法的预处理程序指令,即使字符串x[
在C中没有意义。但你可以将它用作
char Y 10];
声明x
的数组char
。
实际上,C预处理器可以用于C语言之外的其他语言的源文件。例如,它通常用于FORTRAN源。由于FORTRAN没有标准的预处理器。
答案 1 :(得分:2)
首先,你的问题:
断言值文字没有类型是假的吗?
是
没有后缀且没有小数(如100)的值文字总是可以被认为是int类型?
我认为默认情况下,您会输入int
类型。
哪个是文本文字的类型和字形,甚至考虑它的前缀?
如果我没记错,默认类型为char []
。
第二,一些背景:
值文字具有类型 - 它只是没有明确指定,并且不能以这种方式指定所有类型。
通过声明一个常量,您可以明确指定类型,并为编译器提供更多信息。
考虑一下:
#define VALUE1 102
会告诉你你的值是一个int literal。
通过声明一个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 :(得分:2)
它们是正确的,因为预处理器没有类型。
的例子#define VALUE_L 100l
这并不意味着VALUE_L
的类型为long
。您可以使用预处理器将该文本插入字符串文字的中间 - 例如this。
宏没有类型。预处理器可以创建令牌,然后编译器可以将其解释为具有类型 - 但这是切线,并且它不必执行任何此类操作。
此外,L""
文字是C ++ 03和wchar_t
。文字""
具有类型const char[1]
,并且是左值。它们是左值的原因是因为传统上它们用const char*
指向,并且该指针必须指向左值,否则它在变为有用之前将变为无效,而传统的C数组不能是右值。
答案 3 :(得分:2)
为什么常常知道文字值(和#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]
。
使用前缀,字符类型会更改为您在问题中提供的类型;对于包括终结符在内的所有字符,数组大小仍然足够大。
答案 4 :(得分:1)
#define
是预处理器的指令,它只是复制和粘贴样式替换。预处理器不知道或关心代码的含义,也没有类型的概念。
在预处理之后,编译器处理表达式,语句,类型等。每个表达式(除非它是重载函数的名称或地址)都有一个类型,它只依赖于该表达式,而不是代码的上下文。
(C ++ 11的 braced-init-lists 没有类型,并且在技术上不是表达式,尽管它们可以出现在许多相同的上下文中。)
因此#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]
,依此类推。
答案 5 :(得分:0)
#define
告诉预编译器用定义替换所有实例,因此变量中的类型不明确,但可以通过查看它所代表的文字值来确定。
int
,没有任何修饰符,或者可以制作成long
等,如436234636L。答案 6 :(得分:0)
当预处理器看到文本#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]
。