将数组指向相同的内存位置

时间:2018-03-29 18:50:20

标签: c arrays pointers struct

我有两个结构,我无法修改,它们非常相似,但不完全相同。在struct1_t的情况下,第一个变量是指向tstStruct_t结构的指针数组。在struct2_t的情况下,第一个变量只是tstStruct_t结构的数组。

我的目标是将这两个结构“链接”在一起,以便struct2的更改也会导致struct1更改。实现这一目标的想法是将它们都指向同一个内存块。假设这种方法甚至可行,我似乎无法弄清楚如何使其发挥作用。

根据我的理解,struct1.var是指向包含四个连续uint16_t的内存块的开头的指针。因此,有必要说struct1.var = struct2.var只会使struct1.var指向与struct2.var相同的内存位置,而struct2.var的任何更改都会被struct1.var看到。 tst也是如此,上面略有不同。

如何在不进行直接记忆的情况下完成此任务(由于我觉得这个问题没有必要)?是否有可能实现这一目标?

#include <stdio.h>
#include <stdint.h>
#include <string.h>

typedef struct {
    uint16_t tst1;
    uint16_t tst2;
} tstStruct_t;

typedef struct {
    tstStruct_t (*tst)[4];
    uint16_t    var[4];
} struct1_t;

typedef struct {
    tstStruct_t tst[4];
    uint16_t    var[4];
} struct2_t;

int main(int argc, char *argv[])
{
    int i;
    struct1_t  struct1;
    struct2_t  struct2;

    memset(&struct2, 0, sizeof(struct2_t));

    // Print out tst1 from struct1
    printf("tst1: %d\n", struct1.tst[0]->tst1);

    for (i = 0; i < 4; i++) {
        struct1.tst[i] = &(struct2.tst[i]); // WRONG!
    }
    struct1.var = struct2.var; // WRONG!

    struct2.tst[0].tst1 = 1;

    // Print out tst1 from struct1 again, expecting it to now be 1
    printf("frame1: %d\n", struct1.tst[0]->tst1);

    return 0;
}

2 个答案:

答案 0 :(得分:1)

这是我认为有用的东西。它编译但我还没试图运行它:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

typedef struct {
    uint16_t tst1;
    uint16_t tst2;
} tstStruct_t;

typedef struct {
    tstStruct_t (*tst)[4];
    uint16_t    var[4];
} struct1_t;

typedef struct {
    tstStruct_t tst[4];
    uint16_t    var[4];
} struct2_t;

int main(int argc, char *argv[])
{
    int i;
    tstStruct_t mytst[4];
    struct1_t  struct1;
    struct2_t  struct2;

    memset(&struct2, 0, sizeof(struct2_t));

    for (i = 0; i < 4; i++) {
        mytst[i].tst1 = i + 23;
        mytst[i].tst2 = i + 37;
    }

    struct1.tst = &mytst;

    // Print out tst1 from struct1
    printf("tst1: %d\n", struct1.tst[0]->tst1);

    for (i = 0; i < 4; i++) {
        struct2.tst[i] = mytst[i];
    }

    struct1.tst = &struct2.tst;
    for (i = 0; i < 4; i++) {
        struct1.var[i] = struct2.var[i];
    }

    struct2.tst[0].tst1 = 1;

    // Print out tst1 from struct1 again, expecting it to now be 1
    printf("frame1: %d\n", struct1.tst[0]->tst1);

    return 0;
}

<强>更新

  

这绝对是一个有用的开始。但是你的行struct1.var [i] = struct2.var [i]基本上是一个memcpy,我试图避免。

var标量的数组,因此有些复制是不可避免的。根据我之前关于sizeof不同的评论,它不能在一次操作中完成。

从原帖开始:

  

根据我的理解,struct1.var是指向包含四个连续uint16_t的内存块开头的指针

不,它 指针到一块内存。它那块内存。要成为一个指针,它需要是uint16_t *var或[更接近你正在做的事情] uint16_t (*var)[4]

这就是为什么需要手动复制的原因。

memcpy 可以用于var数组但是它[可能]对于这样一个短循环[可能会展开]的速度并不快

并且,struct1.var = struct2.var 编译。

请注意struct1.tst = &struct2.tst可以避免复制数组内容(即它只是一个指针设置)。

要做得更好,需要重新架构结构[你提到过你可以做的]。将varstruct1_t/struct2_t移动到tstStruct_t作为标量(例如uint16_t var

旁注:我已经在C中编程了35年以上而且除了课堂之外我从未[几乎没有]遇到type (*sym)[4]语法(?在SO上张贴的练习。 IMO,相对于它可能提供的好处而言,它很麻烦。 IIRC,我见过的另一个地方[作为一种技巧]是GMP数学库。

答案 1 :(得分:1)

你的问题措辞的方式有点令人困惑,但在阅读了几次之后,我想我明白你想要做什么。

以下提供了一种可以使用的技术。由于我不确定您的实际应用,因此我很难确定这种方法是否真的适合您。因此,如果你能提供一些反馈作为评论,我将不胜感激。

此外,我添加了一个更新,用于使用代理对象将两种类型的结构中的一种struct1_tstruct2_t映射到规范化结构struct1_2_t,然后使用该结构访问实际对象。这种方法需要一个新的结构以及两个映射例程,它们将两种类型之一的对象映射到代理对象。请参阅下面的替代方案 - 使用代理对象

你想要做的是拥有这两个结构中的union但问题是一个struct有一个tstStruct_t tst[4]数组,而另一个结构有一个指针变量tstStruct_t (*tst)[4]。所以两个结构的大小不一样,结构的第二个成员uint16_t var[4]有不同的偏移量。

但是,如果我们希望我们可以选择较大的struct来保存我们的数据struct2_t,然后通过使用预处理器宏执行一些正确初始化的struct1_t变量来访问它指针算术。

这种方法的缺点是,为了通过struct1_t访问内存区域,您需要使用适当的宏。您也将浪费一些空间,因为var的{​​{1}}数组将不会被使用。

这两个宏将使用指向struct1_t的指针和必要的计算来访问适当的区域。 struct1_t要访问TST_PTR()的{​​{1}}和.tst1成员,.tst2将访问struct2_t数组。这些宏还假设结构的数据成员不会有任何异常包装

VAR_PTR()

这是一个在Visual Studio 2017 Community Edition下作为C源代码运行的测试程序。我们所做的是使用.var来创建一个内存区域,然后我们指向#define TST_PTR(p,i) (*(*((p)->tst) + i)) #define VAR_PTR(p,i) *((uint16_t *)(*((p)->tst) + 4)+i) 的{​​{1}}成员,这样两种类型的两个变量都指向同一个内存区域。任何通过struct2_t视图访问都是通过宏完成的。

因此,我们按照以下方式复制您的tst定义:

struct1_t

然后我们可以按如下方式编写测试程序:

struct1_t

此新版本不会在Visual Studio 2017 Community Edition中发出任何警告。

此示例程序为我们提供了

的输出
struct

替代方案 - 使用代理对象

如果我们引入一个代理对象以及两个例程来将每个类型typedef struct { uint16_t tst1; uint16_t tst2; } tstStruct_t; typedef struct { tstStruct_t (*tst)[4]; // tst is a pointer to an array size of 4 elements uint16_t var[4]; } struct1_t; typedef struct { tstStruct_t tst[4]; // tst is an array of size of 4 elements uint16_t var[4]; } struct2_t; #define TST_PTR(p,i) (*(*((p)->tst) + i)) #define VAR_PTR(p,i) *((uint16_t *)(*((p)->tst) + 4)+i) void printStructs(struct1_t struct1, struct2_t struct2) { // get a copy of the pointer to the data area so that we can print // out the data stored there. int i; printf(" Structs\n"); // Print out struct1 view of memory area for (i = 0; i < 4; i++) { printf(" struct1 tst: i = %d %d %d\n", i, TST_PTR(&struct1, i).tst1, TST_PTR(&struct1, i).tst2); } for (i = 0; i < 4; i++) { printf(" struct1 var: i = %d %d \n", i, VAR_PTR(&struct1,i)); } printf("\n"); // Print out struct2 view of memory area for (i = 0; i < 4; i++) { printf(" struct2 tst : i = %d %d %d\n", i, struct2.tst[i].tst1, struct2.tst[i].tst2); } for (i = 0; i < 4; i++) { printf(" struct2 var: i = %d %d \n", i, struct2.var[i]); } printf("\n"); } int main(void) { int i; struct2_t struct2 = { 0 }; struct1_t struct1 = { &struct2.tst, 0 }; // point struct1.tst to struct2.tst so both are using the same memory area. // initialize our struct2 for our explorations to follow. for (i = 0; i < 4; i++) { struct2.tst[i].tst1 = 10 + i; struct2.tst[i].tst2 = 100 + i; struct2.var[i] = i + 1000; } printStructs(struct1, struct2); // test print // modify the area by accessing it through struct1.tst this time. // we are using a temporary pointer in order to work around Visual Studio 2013 // which doesn't seem to like what we are doing here. for (i = 0; i < 4; i++) { TST_PTR(&struct1, i).tst1 *= 2; TST_PTR(&struct1, i).tst2 *= 12; VAR_PTR(&struct1, i) += 120; } printStructs(struct1, struct2); return 0; } 映射到代理对象,我们就可以访问Structs struct1 tst: i = 0 10 100 struct1 tst: i = 1 11 101 struct1 tst: i = 2 12 102 struct1 tst: i = 3 13 103 struct1 var: i = 0 1000 struct1 var: i = 1 1001 struct1 var: i = 2 1002 struct1 var: i = 3 1003 struct2 tst : i = 0 10 100 struct2 tst : i = 1 11 101 struct2 tst : i = 2 12 102 struct2 tst : i = 3 13 103 struct2 var: i = 0 1000 struct2 var: i = 1 1001 struct2 var: i = 2 1002 struct2 var: i = 3 1003 Structs struct1 tst: i = 0 20 1200 struct1 tst: i = 1 22 1212 struct1 tst: i = 2 24 1224 struct1 tst: i = 3 26 1236 struct1 var: i = 0 1120 struct1 var: i = 1 1121 struct1 var: i = 2 1122 struct1 var: i = 3 1123 struct2 tst : i = 0 20 1200 struct2 tst : i = 1 22 1212 struct2 tst : i = 2 24 1224 struct2 tst : i = 3 26 1236 struct2 var: i = 0 1120 struct2 var: i = 1 1121 struct2 var: i = 2 1122 struct2 var: i = 3 1123 或{ {1}}使用代理对象。

代理对象结构和映射例程如下。

struct1_t

可以使用代理对象和映射函数,如以下代码所示。以下功能是:

  • 两个打印函数,用于通过结构和代理打印测试对象

  • 使用代理接受任何一种测试对象的更新函数

源代码如下。

struct2_t