成员结构的值在作为指针传递给函数后丢失

Posted

技术标签:

【中文标题】成员结构的值在作为指针传递给函数后丢失【英文标题】:Values of member struct get lost after being passed to a function as a pointer 【发布时间】:2021-08-17 10:10:54 【问题描述】:

总结:

我有一个问题,我在结构中的指针在传递给函数后会随机化。

所以我传递了原始结构,指针保持不变(我在那里检查它并且它工作),但在传递给函数后,所述指针不再工作。指针指向同一个地址,但结构的内容丢失并随机化,没有任何先前的数据仍然存在。

注意:所有像 ph_ReturnTypeInt 这样的签名都只是专门的类型。我添加了在这种情况下无关紧要的其他数据的结构,除了函数指针签名

注 2:由于有很多代码可能并不重要,我试图解释什么是什么,但如果你需要的话,这里是 GitHub link。如果你能帮助我,谢谢你^^

被调用的函数:

/// Defined wrapper for the function
/// @param call_ctx Call Context for the wrapper
/// @param x Example for how a user argument could look like
ph_ReturnTypeInt DecorateFunc_Wrapper(DecorateFunc_WrapContext *call_ctx, int x)

    printf("Called wrapper\n");

    // ----> Compiler generated ---->

    ph_ReturnTypeInt call_r;

    // Child Context is null -> Reached lowest level of wrapping
    if (!call_ctx->child_ctx && !call_ctx->has_child_ctx)
    
        // Calling the wrapped function
        call_r = call_ctx->wrapped_func(x);
    
    else
    
        // Passing the context down one level to the other function
        call_r = (*call_ctx->child_ctx).wrapper_func(call_ctx->child_ctx, x);
    

    int local_r = call_r.actual_value;
    // <---- Compiler generated <----

    printf("Finished function call\n");

    // ----> Compiler generated ---->

    ph_ReturnTypeInt func_r = 
        .base.is_exception = false,
        .base.is_null = false,
        .actual_value = local_r
    ;

    // <---- Compiler generated <----
    return func_r;

“丢失”其 child_ctx 指针的结构:

/// Context for the DecorateFunc Decorator. Contains a child_ctx element to point to a child if it exists. Contains
/// a wrapper function and wrapped function. The wrapped function should be NULL if child_ctx is populated.
typedef struct DecorateFunc_WrapContext 
    bool has_child_ctx;
    ph_DecoType_Int_Int wrapped_func;
    DecorateFunc_Wrapper_Type wrapper_func;
    DecorateFunc_WrapContext *child_ctx;
 DecorateFunc_WrapContext;

返回结构的函数:

/// Decorates a function and returns a struct containing the func and the wrapper specified for this decorator.
/// @param passable Passable struct that can either contain a function or an initialised wrapped struct that should
/// be wrapped again. In both cases the types must match with the target of the decorator to correctly pass
/// the arguments.
DecorateFunc_WrapContext DecorateFunc(DecorateFunc_WrapContext ctx)

    printf("Called decorator\n");

    // ----> Compiler generated ---->

    DecorateFunc_WrapContext new_ctx;
    // Child Context is null -> Reached lowest level of wrapping / The function does not have any more wrapping
    if (!ctx.child_ctx && !ctx.has_child_ctx && !ctx.wrapper_func)
    
        new_ctx = (DecorateFunc_WrapContext) 
            .has_child_ctx = false,
            .wrapper_func = DecorateFunc_Wrapper,
            .wrapped_func = ctx.wrapped_func,
            .child_ctx = NULL
        ;
    
    else
    
        // Creating a new context and passing the context as a child
        new_ctx = (DecorateFunc_WrapContext) 
            .has_child_ctx = true,
            .wrapper_func = DecorateFunc_Wrapper,
            .child_ctx = &ctx,
        ;
    
    // <---- Compiler generated <----

    return new_ctx;

主要功能:

int main()

    DecorateFunc_WrapContext p;
    p = (DecorateFunc_WrapContext)  .wrapped_func = &main_func ;
    DecorateFunc_WrapContext deco_ctx = DecorateFunc(p);
    deco_ctx.wrapper_func(&deco_ctx, 15);

    /* Wrapping the wrapped context */
    DecorateFunc_WrapContext deco_ctx2 = DecorateFunc(deco_ctx);
    deco_ctx2.wrapper_func(&deco_ctx2, 20);

作为函数指针传递的函数:

ph_ReturnTypeInt main_func(int x)

    printf("Called decorated function - Passed argument: %i\n", x);

    /* Compiler generated return */
    ph_ReturnTypeInt r = 
        .base.is_exception = false,
        .base.is_null = false,
        .actual_value = 3
    ;
    return r;

最后是附加上下文(主文件和其他带有签名的标头,应该不会有太大影响):

// Used content of the header. Other content is just declarations etc.
/* Undefined Base Return which serves as the base for all ReturnTypes */
typedef struct ph_UndefBaseReturn 
    bool is_exception;
    const char* exception;
    const char* traceback;
    bool is_null;
 ph_UndefBaseReturn;

/* Para-C Return of Type int. Compiler-Generated */
typedef struct ph_ReturnTypeInt 
    ph_UndefBaseReturn base;
    int actual_value;
 ph_ReturnTypeInt;

/* Decorator Return Types - Compiler-Generated */

typedef ph_ReturnTypeInt (*ph_DecoType_Int_Int)(int);

// At the top of the main file

typedef struct DecorateFunc_WrapContext DecorateFunc_WrapContext;

/// Signature of the wrapper - Returns int and contains as parameters a int return function and an int
/// This type will be automatically generated for any wrapper, but only used in the decorator for correctly creating
/// the struct which will store the wrapper and wrapped function.
typedef ph_ReturnTypeInt (*DecorateFunc_Wrapper_Type)(DecorateFunc_WrapContext*, int); // R: int - P: struct, int

【问题讨论】:

【参考方案1】:

主要:

/* Wrapping the wrapped context */
DecorateFunc_WrapContext deco_ctx2 = DecorateFunc(deco_ctx);
deco_ctx2.wrapper_func(&deco_ctx2, 20);

在装饰函数中:

DecorateFunc_WrapContext DecorateFunc(DecorateFunc_WrapContext ctx)

...
    
        // Creating a new context and passing the context as a child
        new_ctx = (DecorateFunc_WrapContext) 
            .has_child_ctx = true,
            .wrapper_func = DecorateFunc_Wrapper,
            .child_ctx = &ctx,   // <-- this line
        ;
    

&lt;-- this linechild_ctx 的赋值将new_ctx 链接到main() 中deco_ctx 的临时副本。由于您按值传递结构,因此编译器在堆栈上构建了它的临时副本,然后(可能)在函数完成后重新使用堆栈的该区域。您的链接 (.child_ctx) 现在悬空。

您需要传递 new_ctx 的地址,调整 DecorateFunc 以接受指针,将 .child_ctx 分配给该指针,并调整您的测试以处理指针,它工作

【讨论】:

非常感谢 ^^ 这有效并完美解决了问题。

以上是关于成员结构的值在作为指针传递给函数后丢失的主要内容,如果未能解决你的问题,请参考以下文章

将结构指针向量对的值传递给函数

类成员函数不能作为普通函数地址传递给普通函数指针,几种解决方案

为啥传递给函数的指针的值没有改变? [复制]

将指向成员函数的指针传递给单独的线程

Python & Ctypes:将结构作为指针传递给函数以获取数据

使用变量与指向变量的指针作为函数的参数