user-0 提问: c语言define的迷惑

回复:
user: user-1
content: 以下内容来自ＭＳＤＮ #define identifier[( identifieropt, ... , identifieropt )] token-stringopt A #define without a token-string removes occurrences of identifier from the source file. The identifier remains defined and can be tested using the #if defined and #ifdef directives.

user: user-2
content: 引用 9 楼 zhao4zhong1 的回复:编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E 这才是只需记住的东东！

user: user-3
content: 只需要记住#define不做运算，只做替换。 而#define定义的名称可以在语句中运算  比如 #define q(x) x*(x-1) int sq,y; scanf("%d",&y); printf("%d",sq=q(y));

user: user-4
content: 空值，必须是空值

user: user-2
content: 编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E

user: user-2
content: The #define Directive You can use the #define directive to give a meaningful name to a constant in your program. The two forms of the syntax are:   Syntax  #define identifier token-stringopt  #define identifier[( identifieropt, ... , identifieropt )] token-stringopt  The #define directive substitutes token-string for all subsequent occurrences of an identifier in the source file. The identifier is replaced only when it forms a token. (See C++ Tokens in the C++ Language Reference.) For instance, identifier is not replaced if it appears in a comment, within a string, or as part of a longer identifier.  A #define without a token-string removes occurrences of identifier from the source file. The identifier remains defined and can be tested using the #if defined and #ifdef directives.  The token-string argument consists of a series of tokens, such as keywords, constants, or complete statements. One or more white-space characters must separate token-string from identifier. This white space is not considered part of the substituted text, nor is any white space following the last token of the text.  Formal parameter names appear in token-string to mark the places where actual values are substituted. Each parameter name can appear more than once in token-string, and the names can appear in any order. The number of arguments in the call must match the number of parameters in the macro definition. Liberal use of parentheses ensures that complicated actual arguments are interpreted correctly.   The second syntax form allows the creation of function-like macros. This form accepts an optional list of parameters that must appear in parentheses. References to the identifier after the original definition replace each occurrence of identifier( identifieropt, ..., identifieropt ) with a version of the token-string argument that has actual arguments substituted for formal parameters.   The formal parameters in the list are separated by commas. Each name in the list must be unique, and the list must be enclosed in parentheses. No spaces can separate identifier and the opening parenthesis. Use line concatenation — place a backslash (\) before the newline character — for long directives on multiple source lines. The scope of a formal parameter name extends to the new line that ends token-string.   When a macro has been defined in the second syntax form, subsequent textual instances followed by an argument list constitute a macro call. The actual arguments following an instance of identifier in the source file are matched to the corresponding formal parameters in the macro definition. Each formal parameter in token-string that is not preceded by a stringizing (#), charizing (#@), or token-pasting (##) operator, or not followed by a ## operator, is replaced by the corresponding actual argument. Any macros in the actual argument are expanded before the directive replaces the formal parameter. (The operators are described in Preprocessor Operators.)  The following examples of macros with arguments illustrate the second form of the #define syntax:  // Macro to define cursor lines  #define CURSOR(top, bottom) ((top) << 8) | bottom))  // Macro to get a random integer with a specified range  #define getrandom(min, max) \     ((rand()%(int)(((max) + 1)-(min)))+ (min))  Arguments with side effects sometimes cause macros to produce unexpected results. A given formal parameter may appear more than once in token-string. If that formal parameter is replaced by an expression with side effects, the expression, with its side effects, may be evaluated more than once. (See the examples under Token-Pasting Operator (##).)  The #undef directive causes an identifier’s preprocessor definition to be forgotten. See The #undef Directive for more information.  If the name of the macro being defined occurs in token-string (even as a result of another macro expansion), it is not expanded.  A second #define for a macro with the same name generates an error unless the second token sequence is identical to the first.  Microsoft Specific   Microsoft C/C++ allows the redefinition of a macro, but generates a warning, provided the new definition is lexically identical to a previous definition. ANSI C considers macro redefinition an error. For example, these macros are equivalent for C/C++ but generate warnings:  #define test( f1, f2 ) ( f1 * f2 ) #define test( a1, a2 ) ( a1 * a2 )  END Microsoft Specific  This example illustrates the #define directive:  #define WIDTH       80 #define LENGTH      ( WIDTH + 10 )  The first statement defines the identifier WIDTH as the integer constant 80 and defines LENGTH in terms of WIDTH and the integer constant 10. Each occurrence of LENGTH is replaced by (WIDTH + 10). In turn, each occurrence of WIDTH + 10 is replaced by the expression (80 + 10). The parentheses around WIDTH + 10 are important because they control the interpretation in statements such as the following:  var = LENGTH * 20;  After the preprocessing stage the statement becomes:  var = ( 80 + 10 ) * 20;  which evaluates to 1800. Without parentheses, the result is:  var = 80 + 10 * 20;  which evaluates to 280.  Microsoft Specific   Defining macros and constants with the /D compiler option has the same effect as using a #define preprocessing directive at the beginning of your file. Up to 30 macros can be defined with the /D option.  END Microsoft Specific

user: user-5
content: 就是空的，_EXTERN char tmp[10];相当于char tmp[10];  引用 楼主 abc814251901 的回复:#ifdef pig #define _EXTERN #else #define _EXTERN extern #endif  _EXTERN char tmp[10];  现在的问题是，Pig被定义了，那么这个时候_EXTERN应该是什么值？ 这个时候为什么就是一个定义了呢？ 求指点

user: user-6
content: 这种用法一般用在.h文件中，因为对应的.c文件一般不需要extern声明，而其他的.c文件要用到该变量时就需要加extern了

user: user-7
content: 各路大神很给力啊！

user: user-8
content: 宏定义的实现，定义pig的时候，为空值

user: user-9
content: 我也想問 已經看了答案,謝謝各位大牛

user: user-10
content: pig？你看的是什么代码啊。。

user: user-11
content: 有pig _EXTERN char tmp[10]; 就是 char tmp[10];  没有pig _EXTERN char tmp[10]; 就是 extern char tmp[10];

user: user-12
content: 什么也没有啊！空值的

user: user-13
content: #ifdef pig #define _EXTERN #else #define _EXTERN extern #endif _EXTERN char tmp[10];  如果pig被定义，则_EXTERN被定义为空，下面的_EXTERN char tmp[10];被替换成char tmp[10];，是一个数组定义 如果pig被定义，则_EXTERN被定义为extern，下面的_EXTERN char tmp[10];被替换成extern char tmp[10];，是一个数组声明 宏就是简单的文本替换，如果你觉得不是，那你想太多了，就这样

user: user-14
content: 空值。。。。

user: user-15
content: 宏是一种文本替换而已，不存在值的说法。  #define _EXTERN后面是空的，所以被替换成空的。  VS下可以在项目属性->C/C++ ->预处理器 选项里选择输出宏替换后的文件，你可以去看一下。gcc用-E选项。

user: user-16
content: 现在的问题是，Pig被定义了，那么这个时候_EXTERN应该是什么值？// 是个空值