0

我在主题、文章和 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 中是否可能)它也有constcualifier 并且它是 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

After thinking about all this stuff, I'm pretty confused, so I'm begging for some advice:

  • Why is common knowledge that the literal values (and #defines) have no type but a type can be specified with the literal? in other words: Assert that the value literals have no type is false?
  • A value literal without suffix and no decimals (like 100), can always be considered of type int?
  • Which is the type and qualifiers of the text literals, even considering its prefixes?
4

7 回答 7

4

In C and C++ the preprocessor and the compiler are two separate entities.

The preprocessor that handles #defines and other preprocessor directives has no type system. It manipulates strings of characters. And whatever values these characters represent is left to the compiler itself.

Consider

#define Y x[

This is a legal preprocessor directive, even though the string x[ has no meaning in C. Yet you could use it as

char Y 10];

to declare and array x of char.

In fact C preprocessor can be used on source files for languages other than C. For instance, it is often used for FORTRAN sources. Since FORTRAN does not have a standard preprocessor.

于 2013-01-22T16:14:36.320 回答
2

First, your questions:

Assert that the value literals have no type is false?

Yes.

A value literal without suffix and no decimals (like 100), can always be considered of type int?

I think by default, you get type int.

Wich is the type and cualifiers of the text literals, even considering its prefixes?

If I remember correctly the default type is char [].

Second, some context:

Value literals have a type - it's just that it is not explicitly specified and not all types can be specified that way.

By declaring a constant you can specify the type explicitly and give the compiler a lot more information.

Consider that:

#define VALUE1 102

will tell you that your value is an int literal.

By declaring a const, you can say:

static const int VALUE1 = 102;
static const float VALUE1  = 102;
static const double VALUE1 = 102;
static const unsigned int VALUE1 = 102;

The correct/better way to do the define (correct is a relative term for using define for constants) would be:

#define VALUE1 (int(102))
#define VALUE1 (float(102))
// etc ...

At this point, you're better off adding constants.

于 2013-01-22T16:20:09.640 回答
2

They are correct, in that the preprocessor does not have types. Your example of

#define VALUE_L   100l

This does not mean that VALUE_L has type long. You can use the preprocessor to insert that text in the middle of a string literal- for example, this.

A macro does not have a type. The preprocessor can create tokens that the compiler may then interpret as having a type- but this is tangental and it does not have to do any such thing.

Also, L"" literals are C++03 and wchar_t. A literal "" has type const char[1], and is an lvalue. The reason they are lvalues is because traditionally, they are pointed to with a const char*, and that pointer must point to an lvalue, else it would become invalid before being useful, and traditional C arrays cannot be rvalues.

于 2013-01-22T16:24:05.360 回答
2

Why is common knowledge that the literal values (and #defines) have no type but a type can be specified with the literal? in other words: Assert that the value literals have no type is false?

It's not. Literals all have types, as specified in section 2.14 of the C++11 standard. Preprocessor macros are replaced before literals are interpreted.

A value literal without suffix and no decimals (like 100), can always be considered of type int?

No; a decimal literal is the first of int, long int or long long int that can represent the value. Octal or hex literals may also be unsigned if necessary. Before 2011, long long wasn't considered, since it wasn't a standard type.

So 100 will have type int since it is small enough to be representable by int.

Which is the type and qualifiers of the text literals, even considering its prefixes?

With no prefix, it's an array of const char, large enough to hold all the characters and the zero terminator. So "Text" has type char const[5].

With prefixes, the character type changes to the types you give in the question; the array size is still large enough for all characters including the terminator.

于 2013-01-22T16:28:05.017 回答
1

#define is a directive to the preprocessor, which just does copy-and-paste style replacements. The preprocessor doesn't know or care anything about what the code means, and has no concept of types.

After preprocessing, the compiler deals with expressions, statements, types, and so on. Every expression (unless it is the name or address of an overloaded function) has a type which only depends on that expression, not the context of code.

(C++11's braced-init-lists do not have types, and are not technically expressions although they can appear in many of the same contexts.)

So #define VALUE 100 has meaning to the preprocessor, but at that point the idea of type doesn't even apply. But almost any correct use of VALUE after that will use it as an expression, and those expressions will all have type int.

Yes, the number suffixes and string prefixes do affect the type of a literal expression. The type of 100 is int, but the type of 100UL is unsigned long.

The literal "Text" always has type const char [5], but the exact meaning and representation of char can depend on your compiler. In most contexts, that literal will instantly decay using the implicit array-to-pointer conversion, to the const char* type. (Also, for backward compatibility with ancient C code from before the invention of const, C++ allows initializing a char* variable from a string literal, but it's better to not let that happen.)

Similarly, the literal L"Text" has type const wchar_t [5], and so on.

于 2013-01-22T18:15:37.107 回答
0

A #define tells the precompiler to replace all instances with the definition, so the type is not explicit in the variable, but it can be determined by looking at the literal value it represents.

  • An integer literal is an int without any modifiers, or else can be made into a long etc. like 436234636L.
  • A string literal is a normal string unless appended with modifiers as in your question.
于 2013-01-22T16:07:21.473 回答
0

When the preprocessor sees the text #define VALUE 100, it stores the string VALUE [or something like that], and the "replacement" as 100. Whenever the preprocessor later finds VALUE, it replaces it with 100. As such, VALUE has no type. The text 100 in C does have a type - it is an int, because that's what the rules of the languages say.

Bear in mind that preprocessor replacement happens before the proper compilation, so preprocesor replacement can do all manner of "weird" things that is hard (or sometimes impossible) to do without macros.

Again, the preprocessor simply replaced TEXT with "Text" and at that point it has no type. Types only exist in the proper compiler. So if you have:

#define TEXT "Text"

void myfun(int x)
{
   ... 
}

... 
myfun(TEXT);

the preprocessor will produce

...
myfun("Text");

Only once you get to the proper compiling of the code will the compiler find that "Hmm, this is a text string, it's not an integer as expected", and give you some sort of error.

As to the "type" of "Text", it does depend on the exact context. In most cases, the safe thing to do is treat it as const char *, but in some contexts, it can also be considered char [5].

于 2013-01-22T16:18:08.807 回答