请高手说详细些,分肯定没问题。

解决方案 »

  1.   


    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-stringoptThe #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  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 SpecificThis 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
      

  2.   

    有点象别名,如
    #define PI 3.1415926
    #define CONST const
      

  3.   

    尽量用const和inline而不用#define这个最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。再看下面的语句:#define ASPECT_RATIO 1.653编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不会出现在符号列表中。
    解决这个问题的方案很简单:不用预处理宏,定义一个常量:const double ASPECT_RATIO = 1.653;这种方法很有效。但有两个特殊情况要注意。
    首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,你要写两次const:const char * const authorName = "Scott Meyers";关于const的含义和用法,特别是和指针相关联的问题,参见条款21。另外,定义某个类(class)的常量一般也很方便,只有一点点不同。要把常量限制在类中,首先要使它成为类的成员;为了保证常量最多只有一份拷贝,还要把它定义为静态成员:
        class GamePlayer {
    private:
    static const int NUM_TURNS = 5; // constant eclaration 
    int scores[NUM_TURNS]; // use of constant
    ...
    };还有一点,正如你看到的,上面的语句是NUM_TURNS的声明,而不是定义,所以你还必须在类的实现代码文件中定义类的静态成员:const int GamePlayer::NUM_TURNS; // mandatory definition;
    // goes in class impl.file你不必过于担心这种小事。如果你忘了定义,链接器会提醒你。旧一点的编译器会不接受这种语法,因为它认为类的静态成员在声明时定义初始值是非法的;而且,类内只允许初始化整数类型(如:int, bool, char 等),还只能是常量。
    在上面的语法不能使用的情况下,可以在定义时赋初值:
    class EngineeringConstants { // this goes in the class
    private: // header file
    static const double FUDGE_FACTOR;
    ...
    };
    // this goes in the class implementation file
    const double EngineeringConstants::FUDGE_FACTOR = 1.35;大多数情况下你只要做这么多。唯一例外的是当你的类在编译时需要用到这个类的常量的情况,例如上面GamePlayer::scores数组的声明(编译过程中编译器一定要知道数组的大小)。所以,为了弥补那些(不正确地)禁止类内进行整型类常量初始化的编译器的不足,可以采用称之为“借用enum”的方法来解决。这种技术很好地利用了当需要int类型时可以使用枚举类型的原则,所以GamePlayer也可以象这样来定义:
    class GamePlayer {
    private:
    enum { NUM_TURNS = 5 } // "the enum hack" — makes
    // NUM_TURNS a symbolic name 
    // for 5
    int scores[NUM_TURNS];// fine
    };除非你正在用老的编译器(即写于1995年之前),你不必借用enum。当然,知道有这种方法还是值得的,因为这种可以追溯到很久以前的时代的代码可是不常见的哟。回到预处理的话题上来。另一个普遍的#define指令的用法是用它来实现那些看起来象函数而又不会导致函数调用的宏。典型的例子是计算两个对象的最大值:
    #define max(a,b) ((a) > (b) ? (a) : (b))这个语句有很多缺陷,光想想都让人头疼,甚至比在高峰时间到高速公路去开车还让人痛苦。
    无论什么时候你写了象这样的宏,你必须记住在写宏体时对每个参数都要加上括号;否则,别人调用你的宏时如果用了表达式就会造成很大的麻烦。但是即使你象这样做了,还会有象下面这样奇怪的事发生:int a = 5, b = 0;
    max(++a, b);// a 的值增加了2次
    max(++a, b+10); // a 的值只增加了1次这种情况下,max内部发生些什么取决于它比较的是什么值!
    幸运的是你不必再忍受这样愚笨的语句了。你可以用普通函数实现宏的效率,再加上可预计的行为和类型安全,这就是内联函数(见条款33):
    inline int max(int a, int b) { return a > b ? a : b; }
    不过这和上面的宏不大一样,因为这个版本的max只能处理int类型。但模板可以很轻巧地解决这个问题:
    template<class T>
    inline const T& max(const T& a, const T& b)
    { return a > b ? a : b; }这个模板产生了一整套函数,每个函数拿两个可以转换成同种类型的对象进行比较然后返回较大的(常量)对象的引用。因为不知道T的类型,返回时传递引用可以提高效率(见条款22)。顺便说一句,在你打算用模板写象max这样有用的通用函数时,先检查一下标准库(见条款49),看看他们是不是已经存在。比如说上面说的max,你会惊喜地发现你可以后人乘凉:max是C++标准库的一部分。
    有了const和inline,你对预处理的需要减少了,但也不能完全没有它。抛弃#include的日子还很远,#ifdef/#ifndef在控制编译的过程中还扮演重要角色。预处理还不能退休,但你一定要计划给它经常放长假。
      

  4.   

    定义了宏以后
    #define PI 3.1415926
    编译器会在程序中凡是遇到了“PI”这个词就会自动用3.1415926来代替。
    已定义好的宏是不能赋值的。可以按常量来理解,虽然两者有不同之处。
      

  5.   

    宏对宏扩展的预处理在所有那些不是预处理指令的行(第一个非空白字符不是#的行),以及其指令并未作为条件编译的一部分而忽略的行中进行。“条件编译”指令允许通过检测一个常量表达式或标识符以决定在预处理过程中哪个文本块送入编译器、哪个文本块从源文件中删除,并以此种方式控制一个源文件中某部分的编译。#define指令通常使用有意义的标识符与常量、关键字、常用语句和表达式关联。表示常量的标识符有时被称作“符号常量”或“显式”常量。表示语句或表达式的常量称为“宏”。
    当宏的名称在程序源文本或在某些其它预处理器命令的参量中被识别时,它被处理为对该宏的调用。宏名称被宏体的一个拷贝所替换。若该宏接受参量,宏名称后的实参就会替换宏体中的形参。用宏体中处理的拷贝来替换一个宏调用的过程,称为宏调用的“扩展”。实际的术语中有两种类型的宏。“类对象”宏不带参量,而“类函数”宏可定义为带参量。因此它们的形式和功能都象函数调用,由于宏不生成实际的函数调用,所以有时可用宏替代函数调用使程序运行得更快,(在C++中,inline函数通常是一个好方法),然而,如果不小心的定义和使用宏,也可能造成麻烦。在带参量的宏定义时,你必须使用括号以保持一个表达式中正常的优先级,同时宏也不能正确地处理具有副作用的表达式。一旦你定义了一个宏,你不能不经取消该宏原有定义,而重新定义它为一个不同的值。但可用正好相同的定义来重定义该宏,因此,一个程序中宏的相同定义可出现多次。
    #undef指令用于取消宏的定义。一旦取消该宏的定义,就可重新定义该宏为一个不同的值。用法有:#define 标识符 语言符号字符串
    #define 标识符[(标识符,...,标识符)] 语言符号字符串
    defined( 标识符 )
    defined 标识符
    #undef 标识符
      

  6.   

    nustchenhf() ,你的这些话好像是Effective C++里的啊!
      

  7.   

    宏简单的说就是用一个指定的标识符来代表一个字符串
    分为不带参数和带参数两种,如:
    #define PI 3.14159265
    #define S(a,b)  a*b
    宏不进行类型检查,所以用的时候得小心些
    具体请参考《C程序设计》(清华大学出版社)谭浩强  P142
      

  8.   

    hehe,来晚了。
    我建议你好好看看c,或是c++的教材书!
    打好基础
      

  9.   

    感谢各位的帮忙,我现在一直在坚持学习C++和VC,现在刚找了份工作,使用VC开发的,为了尽快进入角色,只好多问大家低级问题了。