if-else语句在多行宏(C ++)中

时间:2014-03-12 13:54:41

标签: c++ if-statement macros

我实际上有两个问题。

  1. 这是" if(ClassPtr1)&& (ClassPtr2)"检查它们是否为空的正确方法?

  2. 我想知道是否可以在多行宏中完全包含if else语句。我附上了示例代码。

    #define MACRO_NAME(object,expression){\
    Class1* ClassPtr1 = dynamic_cast<Class1*>(object);\
    Class2* ClassPtr2 = ClassPtr1->SomeMethod();\
    if (ClassPtr1) && (ClassPtr2)\
    {\
        try\
        {\
            //some code
        }\
        catch(...)\
        {\
            //some code
        }\
    }\
    else\
        return expression;\
    }
    

7 个答案:

答案 0 :(得分:3)

1:不。您在检查之前使用ClassPtr1,如果它实际上为空,则为未定义的行为。您需要首先获取ClassPtr1,然后检查它,然后使用它来获取ClassPtr2,然后检查它。

2:是的,原则上这很好。宏是否是一个好主意是一个不同的问题。

答案 1 :(得分:0)

1:您可以使用c ++ 11关键字nullptr进行检查。

2:是的,你可以!

答案 2 :(得分:0)

是的,它有效。唯一的问题是你错过了if强制性括号,因此它不会像扩展后那样进行编译。

此外,您必须在访问它们之前检查两个指针​​,否则您将得到未定义的行为,如@Sebastian Redl所指出的那样。

答案 3 :(得分:0)

  1. 语法不太正确;那将是if (ClassPtr1 && ClassPtr2)if的条件必须括在括号中。)

  2. 是的,您可以将任意代码放入宏中。但是您通常应该将多语句宏包装到do { ::: } while (0)构造中,因为它是唯一包含终止;的构造。所以你改变了你的宏:

    #define MACRO_NAME(object, expression) do { \
    /*as before*/ \
    } while (0)
    
  3. 如果没有这个,使用分号后跟宏不会属于您期望的位置。考虑一下:

    if (someCondition)
      MACRO_NAME(a, b);
    else
      doStuff();
    

    您会收到语法错误,因为宏后的;会终止整个if,导致else无法匹配。


    附加说明:您应该在取消引用之前检查ClassPtr1 以获取ClassPtr2

答案 4 :(得分:0)

1)是的,如果修复括号并且在检查它是否为NULL之前不使用可能为NULL的指针,则可以这样做。

2)是的,预处理器给出了OK代码。

使用代码(您的代码有一些修复程序可以编译):

#include <exception>
#include <string>
#define MACRO_NAME(object,expression){\
    Class1* ClassPtr1 = dynamic_cast<Class1*>(object);\
    Class2* ClassPtr2 = ClassPtr1->SomeMethod();\
    if ((ClassPtr1) && (ClassPtr2))\
    {\
            try\
            {\
                        return expression;\
                    }\
            catch(const std::exception& msg)\
            {\
                        ClassPtr2->SomeOtherMethod(msg.what());\
                        return 3;\
                    }\
    }\
    else\
        return expression;\
}

class Class2{public: int SomeOtherMethod(std::string a){return 0;}};
class Class1{public: Class2* SomeMethod(){return 0;}};
int main()
{
    Class1* a;
    MACRO_NAME(a,2);
}

正在运行

cpp macro.cpp | tail -7

将产生

class Class2{public: int SomeOtherMethod(std::string a){return 0;}};
class Class1{public: Class2* SomeMethod(){return 0;}};
int main()
{
 Class1* a;
 { Class1* ClassPtr1 = dynamic_cast<Class1*>(a); Class2* ClassPtr2 = ClassPtr1->SomeMethod(); if ((ClassPtr1) && (ClassPtr2)) { try { return 2; } catch(const std::exception& msg) { ClassPtr2->SomeOtherMethod(msg.what()); return 3; } } else return 2;};
}

答案 5 :(得分:0)

具有控制结构(如循环或if / else)的多行宏是可能的。最佳实践(在避免之后;-))就是将所有内容包装在&#34; do {...} while(false)&#34;像这样:

#define MACRO_NAME(object,expression)\
do { if(...) { doSomething; } else { doSomethingElse; } } while(false)

do ... while循环在语法上与单个语句兼容,而不是普通块或if ... else。例如,它可以很好地与用户在其后面写的分号一起使用。您可以在if .. else:

中使用它
if(cond) MACRO(); else exit();

不会根据你的建议进行编译,因为MACRO后面的分号会创建第二个空的语句,以便&#34; else&#34;晃来晃去。做...而不是这样。

答案 6 :(得分:0)

  

我实际上有两个问题。       这是&#34; if(ClassPtr1)&amp;&amp; (ClassPtr2)&#34;检查它们是否为空的正确方法?

是的,检查是正确的。宏虽然有一些问题(见下文)。

I want to know if it is possible to include an if else statement completely inside a multi-line macro. I have attached example code.

是。以下是您的宏的一些问题(以及为什么您不应该使用宏代替函数):

  • 在检查第一个指针是否为空之前,您将取消引用第一个指针;
  • 宏看起来像一个函数,但它不能这样使用。

考虑这个客户端代码:

if(some_condition)
    MACRO_NAME(MyObject, a+b);

评估结果为:

if(some_condition)
    Class1* ClassPtr1 = dynamic_cast<Class1*>(object);
Class2* ClassPtr2 = ClassPtr1->SomeMethod();
// ...

这很可能不是你想要的(因为ClassPtr2声明会发出编译错误 - 在if块中本地定义了ClassPtr1。)

解决方案:

  1. 使用do {} while(false)围绕宏中的代码。这将确保宏扩展为单个代码块。宏将起作用,但仍然会产生使用宏编写代码所固有的所有问题。

  2. 用引发异常的模板函数替换宏(这是正确的解决方案)。作为(非通用)经验法则,使用宏编写重复代码是API设计不完整的症状(就像使用dynamic_cast是不良类层次结构设计的症状一样)。