【问题标题】:Variadic C function with custom type具有自定义类型的可变 C 函数
【发布时间】:2018-05-14 19:08:31
【问题描述】:

我想实现一个获取自定义类型参数的可变参数函数,不像 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;
}

【问题讨论】:

    标签: variadic-functions apr


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 2016-04-14
      • 2018-10-04
      • 2013-09-13
      • 1970-01-01
      • 2015-06-14
      • 1970-01-01
      • 1970-01-01
      • 2012-10-17
      • 1970-01-01
      相关资源
      最近更新 更多