断言值文字没有类型是假的?

时间:2013-01-22 16:05:06

标签: c++ c++11 types c-preprocessor literals

我已经阅读了#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 * constconst 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类型?
  • 文本文字的类型和限定符是什么,即使考虑其前缀?

7 个答案:

答案 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类型?

没有;十进制文字是可以表示该值的intlong intlong 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]