将NULL作为参数传递给C宏

时间:2017-05-11 01:47:13

标签: c struct

我正在尝试定义一个宏 -

#define macro1(arg1) \
 do{ \
  int _state = 0; \
  if (arg1 && arg1->member_) \
    _state = arg1->member_->state_; \
  printf("%d", _state); \
 } while(0)

A *a = new A():
macro1(a);  // Works
macro1(NULL); // Error

我看到的具体错误是 -

  

"错误:' - >'的基本操作数不是指针"

Aren我们允许将NULL作为参数传递给宏吗?

5 个答案:

答案 0 :(得分:2)

宏扩展只是文本替换,因此当您通过NULL时,它会扩展为NULL->member,显然这是一个错误。一种方法是使用临时变量:

#define macro1(arg1) \
 do{ \
  A* p = (arg1);
  int _state = 0; \
  if (p && p->member_) \
    _state = p->member_->state_; \
  printf("%d", _state); \
 } while(0)

A *a = new A():
macro1(a);
macro1(NULL);

这样两种情况都可以。

答案 1 :(得分:2)

你必须了解什么是宏才能理解你的错误。除了编译器之外,还有一种叫做预编译器的动物。它通过为此宏定义的实际代码替换所有宏的引用。所以这段代码:

#define macro1(arg1) \
 do{ \
  int _state = 0; \
  if (arg1 && arg1->member_) \
    _state = arg1->member_->state_; \
  printf("%d", _state); \
 } while(0)

A *a = new A():
macro1(a);  // Works
macro1(NULL); // Error

将替换为:

A *a = new A():
do{
  int _state = 0;
  if (a && a->member_)
    _state = a->member_->state_;
  printf("%d", _state);
 } while(0)
do{
  int _state = 0;
  if (NULL && NULL->member_)
    _state = NULL->member_->state_;
  printf("%d", _state);
 } while(0)

将编译此代码。现在,您可以自己查看编译错误的根本原因。

答案 2 :(得分:1)

宏只是一个文本替代品。

例如,如果你有

#define mac(x) x/x

适用于必须数字但不适用于0,因为它将替换为未定义的0/0

如果您通过NULL,则会将其替换为:

 do{ \
  int _state = 0; \
  if (NULL && NULL->member_) \
    _state = NULL ->member_->state_; \
  printf("%d", _state); \
 } while(0)

那么NULL->member_在这种情况下的意义是什么。没有意义,因此失败了。

考虑使用常规函数,或者两个宏用于常规指针,一个用于NULL指针,并将代码设置为:

if (ptr)
   macro1(ptr);
else
   macro2;

答案 3 :(得分:1)

小调整让预编译器知道类型大小+前向声明,它将起作用:

#define macro1(arg1) \
 do{ \
  int _state = 0; \
  if ((arg1) && ((A*)arg1)->member_) \
    _state = ((A*)arg1)->member_->state_; \
  printf("%d", _state); \
 } while(0)

完整代码:

#include <stdio.h>

class A;

#define macro1(arg1) \
do{ \
  int _state = 0; \
  if ((arg1) && ((A*)arg1)->member_) \
    _state = ((A*)arg1)->member_->state_; \
  printf("%d", _state); \
} while(0)

struct member{
    int state_;
  };
class A {
  public:
  member* member_;
};


int main(int n, char** arg) {

  A* a = new A();
  a->member_ = new member();
  a->member_->state_ = 1;

  macro1(a);
  macro1(NULL);

  return 0;
}

答案 4 :(得分:1)

更基本的问题是#.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler .handlers = 1catalina.org.apache.juli.FileHandler #1catalina.org.apache.juli.FileHandler.level = FINE #1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs #1catalina.org.apache.juli.FileHandler.prefix = catalina. 1catalina.java.util.logging.FileHandler.level = FINE 1catalina.java.util.logging.FileHandler.pattern = ${catalina.base}/logs/catalina.%g.log 1catalina.java.util.logging.FileHandler.limit = 13107200 1catalina.java.util.logging.FileHandler.count = 5 1catalina.java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter 不是指针,它是0的宏。

因此,当你传入NULL时,它相当于传入0,这当然是一个错误。

正如其他答案所提到的,给论证一个明确的演员会解决它

NULL

作为旁注,您应该在C ++中使用(A*)arg1 作为空指针。

编辑:正如@AjayBrahmakshatriya所指出的那样,nullptr可以定义为NULL(仅限C),这将是一个指针,但参数仍然成立, (void*)0不是您的类型的指针。

EDIT2 :显然在C ++ 11及更高版本中,NULL可以定义为NULL