проверка nullptr на доступ к указателю связанного члена

#c #c #boost #libxml2 #boost-preprocessor

#c #c #повышение #libxml2 #boost-препроцессор

Вопрос:

 typedef struct _xmlNode xmlNode;
typedef xmlNode *xmlNodePtr;
struct _xmlNode {
    void           *_private;   /* application data */
    xmlElementType   type;  /* type number, must be second ! */
    const xmlChar   *name;      /* the name of the node, or the entity */
    struct _xmlNode *children;  /* parent->childs link */
    struct _xmlNode *last;  /* last child link */
    struct _xmlNode *parent;    /* child->parent link */
    struct _xmlNode *next;  /* next sibling link  */
    struct _xmlNode *prev;  /* previous sibling link  */
    struct _xmlDoc  *doc;   /* the containing document */

    /* End of common part */
    xmlNs           *ns;        /* pointer to the associated namespace */
    xmlChar         *content;   /* the content */
...
}
 

Есть узел, подобный указанному выше, и предположим, что у него есть xmlNode node (нет NULL ).
Один хочет получить доступ
node->next->children->next->next->content
но поскольку каждый указатель может быть NULL , нужно проверять их все.

 if(node == NULL || node->next == NULL || node->next->children == NULL ...)
  fprintf(stderr, "err");
 

Есть ли способ проверить, является ли указатель нулевым автоматически? Например

 #define CHECK(ptr) BOOST_PP_????(...) ??

if (CHECK(node->next->children->next->next->content))
 ...
 

_xmlNode это из libxml2, и поскольку я обращаюсь к участникам в проанализированных данных HTML, чтобы получить определенный элемент для обхода веб-сайта, доступ не может быть регулярным, как показано ниже.

 bool go_next(xmlNode n, int num) {
  for(; num; --num) {
    if(n==NULL) return false;
    n = n->next;
  }
  return true;
}
 

Комментарии:

1. Почему тег «с»?

2. @UlrichEckhardt метание просто для объяснения.

Ответ №1:

Тривиально использовать enum и составной литерал, что-то вроде:

 enum {END, PREV, NEXT, CHILDREN, CONTENTS};

int check_node(xmlNode node, int test[])
{
    while ((node != NULL) amp;amp; (*test != END))
    {
        switch (*test)
        {
            case PREV:
                node = node->prev;
                break;
            case NEXT:
                node = node->next;
                break;
            case CHILDREN:
                node = node->children;
                break;
            case CONTENTS:
                node = node->contents;
                break;
            default:
                return 0;
        }
        test  ;
    }
    return (node != NULL);
}

if (!check_node(node, (int []){NEXT, CHILDREN, NEXT, NEXT, CONTENTS, END}))
{
    fprintf(stderr, "err");
}