简体   繁体   English

将内存转换为结构指针

[英]Casting memory into a struct pointer

When I do something like: 当我做的事情:

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

struct my_struct a;

and in a function: 并在一个功能:

void a_func(struct my_struct *a) {
    a = (struct my_struct *) [a memory location];
}

I do not get correct values in a; 我没有得到正确的价值;

but when I do something like: 但当我做的事情如下:

void a_func(struct my_struct *a) {
    *a = *(struct my_struct *) [same memory location];
}

I get correct values in the struct; 我在struct中得到了正确的值;

Any reasonable explanation for this? 对此有任何合理的解释吗?

Lets look at three different cases: 让我们看看三种不同的情况:

  1. Change pointer locally 在本地更改指针

     void foo(S *a) { a = p; } S* b; foo(b); 

    a is a pointer and this function changes the pointer a . a是指针,此函数更改指针a It does not change the object a is pointing to. 它不会更改a指向的对象。 It also does not change b or the object b is pointing to. 它也不会改变bb指向的对象。

  2. Change object pointed to 更改对象指向

      void foo(S *a) { *a = *p; } S* b = ...; foo(b); 

    *a = *p performs a deep copy. *a = *p执行深层复制。 It copies the object pointed to by p over the object pointed to by a . 它将p指向的对象复制到a指向的对象上。 As b points to the same object as a , b will also see these changes. 由于b指向同一个对象作为ab也将看到这些变化。

  3. Get pointer for usage outside the function 获取在函数外部使用的指针

      void foo(S **a) { *a = p; } S* b; foo(&b); 

    Now the function foo accepts a pointer to a pointer. 现在函数foo接受指向指针的指针。 By writing *a = p we change the pointer pointed to by a to p . 通过编写*a = p ,我们改变指针指向ap This can be used to retrieve the pointer p as b will be the same as p after the call to foo . 这可用于检索指针p因为在调用foo之后b将与p相同。

I assume you call that function and then try to use the a parameter after the function returned, eg 我假设您调用该函数,然后尝试在函数返回后使用a参数,例如

a_func(a);
printf("a->n: %u", a->n);

In both cases, you pass the pointer a by value. 在这两种情况下,你通过指针a按值。 Changing the pointer itself in a_func() will not be reflected outside of a_func() . a_func()更改指针本身不会反映在a_func() Put another way, a inside of a_func() is a copy of a outside, so changes to the pointer will not reflected outside after returning. 换句话说, a内部a_func()是副本a外面,所以指针变化不会回国后外部的反射。

Changing the memory a points to will be visible outside, though. 但是,更改内存的点将在外部可见。

In the first case (without * ), you assign a itself in a_func() . 在第一种情况下(没有* ),您在a_func()指定a自身。 As just explained, the new value of a will be lost as soon as a_func() returns. 正如刚刚解释的那样, a_func()返回后, a的新值将丢失。

In the second case (with * ), you copy the memory from [a memory location] the memory pointed to by a . 在第二种情况下(与* ),复制从存储器[a memory location]所述存储器通过指向a This means, that the memory a points to has to be valid: either it has to be on the stack, or dynamically allocated on the heap. 这意味着,存储器a点必须是有效的:要么它必须是在堆栈上,或在堆上动态分配的。 Passing an uninitialized struct my_struct * pointer will lead to crashes sooner or later. 传递未初始化的struct my_struct *指针迟早会导致崩溃。

Once you return, you can access the data copied via the a pointer you passed to a_func() . 返回后,您可以访问通过传递给a_func() a指针复制的数据。

Example for correctly using the copy version (with * ) with a local variable 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.

Another correct version with a allocated on the heap: 另一种正确的版本有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!

A broken example: 一个破碎的例子:

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!

It's the same as trying to change an integer from 3 to 5 inside a function and then failing. 它与尝试在函数内部将整数从3更改为5然后失败相同。 Check the following example: 请检查以下示例:

#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;
}

This is because, when you pass x variable into func here, you pass its value, that is 3 ; 这是因为,当你将x变量传递给func ,你传递它的值,即3 ; func creates a variable named a , assigns it with the passed value 3 , assigns it again with the value 5 . func创建一个名为a的变量,用传递的值3赋值,再次赋值为5 No change has been made to x there, so x still is just 3 . 没有对x进行任何更改,因此x仍然只有3

If you were to pass the address of x as a value to some other function that takes an address as an argument, then access the contents of that address and change it, then you'd be able to remotely change the x , as in the following example: 如果您将x的地址作为值传递给另一个以地址作为参数的函数,那么访问该地址的内容并进行更改,然后您就可以远程更改x ,如以下示例:

#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;
}

Same story for your case, only with one further step of referencing/dereferencing. 您的案例也是如此,只需要进一步引用/解除引用。 If you want to make the first version work out, make changes similar to the following: 如果要使第一个版本正常运行,请进行类似以下的更改:

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;
}

Here, the a_func takes the address of an address-holding variable (pointer) as an argument, and stores that inside a newly created variable called a , which is a variable that holds address to an address to a struct my_struct . 这里, a_func将地址保持变量(指针)的地址作为参数,并将其存储在一个名为a的新创建的变量中,该变量是一个将地址保存到struct my_struct的地址的变量。 Then it accesses the contents of the address a holds, assigns that with a memory location, and so on... 然后它访问a保持的地址的内容,将其分配给内存位置,依此类推......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM