Variadic C函数与自定义类型

时间:2018-05-14 19:08:31

标签: variadic-functions apr

我想实现一个variadic函数,它获取自定义类型参数,而不像GNU的例子:

https://www.gnu.org/software/libc/manual/html_node/Variadic-Example.html#Variadic-Example

在我的逻辑中,我处理节点,由此tpye定义:

typedef struct node_t {
    char *key;
    node_type_t type;
    apr_array_header_t *arr_strings;
    apr_array_header_t *arr_numbers;
} node_t;

这样的节点根据以这种方式定义的特定类型(字符串,数字)类型在不同的APR数组中存储信息:

typedef enum node_type_t {
    node_type_string,
    node_type_number,
} node_type_t;

该功能如下所示:

int add_node(apr_pool_t *p_pool, node_t *p_target_node, ...) {
    int rv = 0;
    va_list lmnts;
    va_start(lmnts, p_target_node);
    node_t *n = va_arg(lmnts, node_t *);
    apr_array_header_t *tbl;
    do {
        switch(n->type) {
            case node_type_string:
                tbl = p_target_node->arr_strings;
                break;
            case node_type_number:
                tbl = p_target_node->arr_numbers;
                break;
            default:
                break;
        }
        printf("\t\t%d - %s\n", rv, n->key);
        *(const node_t**)apr_array_push(tbl) = n;
        rv++;
    } while (n && ((n = va_arg(lmnts, node_t *)) != NULL) &&   apr_strnatcmp(n->key, p_target_node->key) != 0);
    va_end(lmnts);
    return rv;
}

它适用于两个 node_t 参数但是对于更多我得到分段错误。

这是完整的代码:

#include <stdarg.h>
#include <stdio.h>

#include <apr_general.h>
#include <apr_hash.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_tables.h>

typedef enum node_type_t {
    node_type_string,
    node_type_number,
} node_type_t;

typedef struct node_t {
    char *key;
    node_type_t type;
    apr_array_header_t *arr_strings;
    apr_array_header_t *arr_numbers;
} node_t;

node_t *create_node(apr_pool_t *p_pool, char *p_key, node_type_t p_type) {
    node_t *NODE = apr_palloc(p_pool, sizeof(node_t));
    NODE->key = p_key;
    NODE->type = p_type;
    NODE->arr_strings = apr_array_make(p_pool, 0, sizeof(node_t*));
    NODE->arr_numbers = apr_array_make(p_pool, 0, sizeof(node_t*));
    return NODE;
}

int add_node(apr_pool_t *p_pool, node_t *p_target_node, ...) {
    int rv = 0;
    va_list lmnts;
    va_start(lmnts, p_target_node);
    node_t *n = va_arg(lmnts, node_t *);
    apr_array_header_t *tbl;
    do {
        switch(n->type) {
            case node_type_string:
                tbl = p_target_node->arr_strings;
                break;
            case node_type_number:
                tbl = p_target_node->arr_numbers;
                break;
            default:
                break;
        }
        printf("\t\t%d - %s\n", rv, n->key);
        *(const node_t**)apr_array_push(tbl) = n;
        rv++;
    } while (n && ((n = va_arg(lmnts, node_t *)) != NULL) && apr_strnatcmp(n->key, p_target_node->key) != 0);
    va_end(lmnts);
    return rv;
}

int add_node(apr_pool_t *p_pool, node_t *p_target_node, ...) {
    int rv = 0;
    va_list lmnts;
    va_start(lmnts, p_target_node);
    node_t *n = va_arg(lmnts, node_t *);
    while((n = va_arg(lmnts, node_t *)) != NULL && apr_strnatcmp(n->key, p_target_node->key) != 0) {
        printf("\t\t%d - %s\n", rv, n->key);
        *(const node_t**)apr_array_push(p_target_node->arr_strings) = n;
        rv++;
    }
    va_end(lmnts);
    return rv;
}

int main(int argc, const char *argv[]) {
    apr_status_t rv;
    apr_pool_t *mp;

    rv = apr_initialize();
    if (rv != APR_SUCCESS) {
        return -1;
    }
    apr_pool_create(&mp, NULL);

    node_t *ROOT_NODE = create_node(mp, "THE_ROOT", node_type_string);
    printf("\tROOT_NODE { key: '%s', type: %d, [%d, %d]}\n", 
        ROOT_NODE->key, ROOT_NODE->type,
        ROOT_NODE->arr_strings->nelts, ROOT_NODE->arr_numbers->nelts);

    node_t *NODE_A = create_node(mp, "A", node_type_string);
    printf("\tNODE_A { key: '%s', type: %d, [%d, %d]}\n", 
        NODE_A->key, NODE_A->type,
        NODE_A->arr_strings->nelts, NODE_A->arr_numbers->nelts);

    node_t *NODE_B = create_node(mp, "B", node_type_number);
    printf("\tNODE_B { key: '%s', type: %d, [%d, %d]}\n", 
        NODE_B->key, NODE_B->type,
        NODE_B->arr_strings->nelts, NODE_B->arr_numbers->nelts);

    node_t *NODE_C = create_node(mp, "C", node_type_string);
    printf("\tNODE_C { key: '%s', type: %d, [%d, %d]}\n", 
        NODE_C->key, NODE_C->type,
        NODE_C->arr_strings->nelts, NODE_C->arr_numbers->nelts);

    add_node(mp, ROOT_NODE, NODE_A, NODE_B, NODE_C);

    printf("\tn = %d, n = %d\n", ROOT_NODE->arr_strings->nelts, ROOT_NODE->arr_numbers->nelts);

    apr_pool_destroy(mp);
    apr_terminate();
    return 0;
}

1 个答案:

答案 0 :(得分:1)

我看到的问题是你的add_node()似乎检查了一个NULL参数来确定参数列表已经完成,但是当你调用时你永远不会传递NULL参数它,所以add_node将继续阅读不存在的“参数”,在它通过您传递的所有参数后,访问内存中不应该存在的位置,并导致各种不良问题。