我有两个结构,我无法修改,它们非常相似,但不完全相同。在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;
}
答案 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
可以避免复制数组内容(即它只是一个指针设置)。
要做得更好,需要重新架构结构[你提到过你可以做的]。将var
从struct1_t/struct2_t
移动到tstStruct_t
作为标量(例如uint16_t var
)
旁注:我已经在C中编程了35年以上而且除了课堂之外我从未[几乎没有]遇到type (*sym)[4]
语法(?在SO上张贴的练习。 IMO,相对于它可能提供的好处而言,它很麻烦。 IIRC,我见过的另一个地方[作为一种技巧]是GMP
数学库。
答案 1 :(得分:1)
你的问题措辞的方式有点令人困惑,但在阅读了几次之后,我想我明白你想要做什么。
以下提供了一种可以使用的技术。由于我不确定您的实际应用,因此我很难确定这种方法是否真的适合您。因此,如果你能提供一些反馈作为评论,我将不胜感激。
此外,我添加了一个更新,用于使用代理对象将两种类型的结构中的一种struct1_t
或struct2_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