C 将内存强制转换为结构指针

C 将内存强制转换为结构指针,c,struct,casting,C,Struct,Casting,当我做以下事情时: struct my_struct { uint32_t n; double d; uint64_t *ptr; size_t val; }; struct my_struct a; void a_func(struct my_struct *a) { *a = *(struct my_struct *) [same memory location]; } 在函数中: void a_func(struct my_struct

当我做以下事情时:

struct my_struct {
    uint32_t n;
    double   d;
    uint64_t *ptr;
    size_t   val;
};

struct my_struct a;
void a_func(struct my_struct *a) {
    *a = *(struct my_struct *) [same memory location];
}
在函数中:

void a_func(struct my_struct *a) {
    a = (struct my_struct *) [a memory location];
}
我没有得到一个正确的值

但是当我做一些类似的事情时:

struct my_struct {
    uint32_t n;
    double   d;
    uint64_t *ptr;
    size_t   val;
};

struct my_struct a;
void a_func(struct my_struct *a) {
    *a = *(struct my_struct *) [same memory location];
}
我在结构中得到正确的值


对此有何合理解释?

我假设您调用该函数,然后在函数返回后尝试使用
a
参数,例如

a_func(a);
printf("a->n: %u", a->n);
在这两种情况下,都是通过值传递指针
a
。在
a_func()
中更改指针本身不会反映在
a_func()
之外。换句话说,
a
a_func()
内部是
a
外部的副本,因此返回后指针的更改不会反映在外部

不过,将a点的内存更改为将在外部可见

在第一种情况下(不带
*
),在
a_func()
中指定
a
本身。如前所述,
a
的新值将在
a_func()
返回后立即丢失

在第二种情况下(使用
*
),您从
[内存位置]
复制
a
指向的内存。这意味着,
a
指向的内存必须有效:要么在堆栈上,要么在堆上动态分配。传递未初始化的
struct my_struct*
指针迟早会导致崩溃

返回后,可以通过传递到
a_func()
a
指针访问复制的数据

正确使用本地变量
a
的复制版本(带
*
)的示例:

struct my_struct a;         // Allocate a my_struct object on the stack.
a_func(&a);                 // Copy data from [some memory location] into a.
printf("a.n: %u", a.n);     // Access and use the newly copied data in a.
另一个在堆上分配了
a
的正确版本:

// Allocate a my_struct object on the heap and make a point to that memory.
struct my_struct *a = malloc(sizeof(my_struct)); 
a_func(a);                  // Copy data from [some memory location] into a.
printf("a->n: %u", a->n);   // Access and use the newly copied data in a.
free(a);                    // Take care to free the allocated memory when finished!
一个失败的例子:

struct my_struct *a;        // An uninitialized pointer!
a_func(a);                  // The memory location a points to is overwritten - BUG!
printf("a->n: %u", a->n);   // May still work but you corrupted your memory with
                            // the previous function call. This will lead to crashes!

让我们看三种不同的情况:

  • 本地更改指针

    a
    是指针,此函数可更改指针
    a
    。它不会更改
    a
    所指向的对象。它也不会改变
    b
    b
    所指向的对象

  • 更改指向的对象

     void foo(S *a) {
         *a = *p;
     }
     S* b = ...;
     foo(b);
    
    *a=*p
    执行深度复制。它将
    p
    指向的对象复制到
    a
    指向的对象上。由于
    b
    指向与
    a
    相同的对象,
    b
    也将看到这些更改

  • 获取函数外部使用的指针

     void foo(S **a) {
         *a = p;
     }
     S* b;
     foo(&b);
    
    现在函数
    foo
    接受指向指针的指针。通过写入
    *a=p
    我们将
    a
    指向的指针更改为
    p
    。这可用于检索指针
    p
    ,因为调用
    foo
    b
    将与
    p
    相同


  • 这与在函数中尝试将整数从3更改为5,然后失败是一样的。检查以下示例:

    #include <stdio.h>
    
    void func( int a ) {
        a = 5;
    }
    
    int main ( ) {
        int x = 3;
        func( x );
        printf( "%d", x );
        // prints 3 not 5
    
        return 0;
    }
    
    #include <stdio.h>
    
    void anotherfunc( int * a ) {  // a is an address-holding variable
        *a = 5;  // *a is the content of that address and we are changing it to 5
    }
    
    int main ( ) {
        int x = 3;
        func( &x );  // passing the address of the variable x
        printf( "%d", x );
        // prints 5 now
    
        return 0;
    }
    
    对于您的案例,情况也一样,只需进一步参考/取消参考。如果要使第一个版本生效,请进行类似于以下内容的更改:

    void a_func(struct my_struct ** a) {  // added an asterisk
        *a = (struct my_struct *) [a memory location];
    }
    
    // ...
    
    int main( ) {
        // ...
        struct my_struct * x;
        a_func( &x );
    
        // ...
        return 0;
    }
    

    这里,
    a_func
    将地址保持变量(指针)的地址作为参数,并将其存储在新创建的名为
    a
    的变量中,该变量将地址保持在
    struct my_struct
    的地址中。然后它访问地址
    a
    保持的内容,分配一个内存位置,等等…

    改变指针不会改变它(用来)指向的内存。请提供可编译的示例。顺便说一句:这个
    结构我的结构a{
    应该是
    结构我的结构{
    。如果您这样做,请注意对齐要求。如果内存未对齐,您的程序很容易崩溃。@Cornstalks您能给出更好地理解此问题的指针吗?#pragma捆绑将有帮助吗?