早上好,我正在努力想出一种数据结构,它可以在不同的应用程序中使用,但作为相同的类型传递给传输功能,我现在使用的是netbeans,但是这将被传输到dspic30f (16位),
typedef union {
union {
struct {
unsigned bit0 : 1;
unsigned bit1 : 1;
unsigned bit2 : 1;
unsigned bit3 : 1;
unsigned bit4 : 1;
unsigned bit5 : 1;
unsigned bit6 : 1;
unsigned bit7 : 1;
unsigned bit8 : 1;
unsigned bit9 : 1;
unsigned bit10 : 1;
unsigned bit11 : 1;
union {
struct {
unsigned bit12 : 1;
unsigned bit13 : 1;
unsigned bit14 : 1;
unsigned bit15 : 1;
};
unsigned char value;
} lastfour;
};
unsigned int value : 16;
};
union {
struct {
union {
struct {
unsigned bit0 : 1;
unsigned bit1 : 1;
unsigned bit2 : 1;
unsigned bit3 : 1;
};
unsigned char value;
} firstfour;
unsigned bit4 : 1;
unsigned bit5 : 1;
unsigned bit6 : 1;
unsigned bit7 : 1;
unsigned bit8 : 1;
unsigned bit9 : 1;
unsigned bit10 : 1;
unsigned bit11 : 1;
unsigned bit12 : 1;
unsigned bit13 : 1;
unsigned bit14 : 1;
unsigned bit15 : 1;
};
unsigned int value : 16;
};
} foo;然后,我使用下面的代码检查功能。
int main(int argc, char** argv) {
foo a;
a.value =0;
a.lastfour.value = 0xF;
printf("%d", a.value);
return (EXIT_SUCCESS);
}打印的值是0,但是由于合并,我认为这两个结构共享相同的内存(16位),因此在将‘last-4’设置为0xF ' value‘之后,现在应该是0xF 000。
有人能给我指点一下我做错了什么,以及为什么“价值”没有读取包含“最后四”的相同的记忆。
发布于 2015-03-20 15:39:39
首先,我很惊讶这甚至会为你编写。在您的unions类型中有两个匿名foo,它们有重复的成员名(bit4、bit5等)。你的代码不是为我编译的。您应该为这两个unions提供名称或重命名bits,这样它们就不会发生冲突。
其次,您的联合firstfour和lastfour最终可能是8位,而不是4位,因为char的最小大小是8位。会把你的其他部分都抛之脑后。
第三,您的联合firstfour和lastfour不会在内存中的第12位开始。它们将根据需要对齐您的处理器,可能在下一个2字节或4字节偏移量处。尝试在您的函数中打印sizeof(foo)。我保证你会看到像4或8这样的东西,而不是你期待的2。
第四,更大的大小就是为什么您看到测试代码中打印的值"0“。前16位都是零。您设置的0xF要么在接下来的16位中,要么可能在下一个32位中,这取决于编译器对齐的方式。
这里有一个结构布局,应该适合您所要做的工作。我测试过了它对我有用。将所有内容打包成2个字节。
typedef struct {
union {
struct {
uint16_t firstfour : 4;
uint16_t secondfour : 4;
uint16_t thirdfour : 4;
uint16_t lastfour : 4;
};
/* EDIT - Duplicate structure with different member names
added, in response to a comment below. */
struct {
uint16_t nibble1 : 4;
uint16_t nibble2 : 4;
uint16_t nibble3 : 4;
uint16_t nibble4 : 4;
};
struct {
uint16_t bit0 : 1;
uint16_t bit1 : 1;
uint16_t bit2 : 1;
uint16_t bit3 : 1;
uint16_t bit4 : 1;
uint16_t bit5 : 1;
uint16_t bit6 : 1;
uint16_t bit7 : 1;
uint16_t bit8 : 1;
uint16_t bit9 : 1;
uint16_t bit10 : 1;
uint16_t bit11 : 1;
uint16_t bit12 : 1;
uint16_t bit13 : 1;
uint16_t bit14 : 1;
uint16_t bit15 : 1;
};
uint16_t value;
};
} foo;发布于 2015-03-20 11:39:16
它是定义的实现(取决于int-s、处理器、痴呆症、ABI等的大小)。在带有ARM处理器的Android平板电脑上,以及在x86-64桌面上,运行64位版本的Linux (发行版)肯定会有所不同。
我认为您应该避免在union-s中使用struct中的位字段,除非您正在考虑特定的实现。
我不确定您的代码是否允许您调用任意函数(特别是,因为指针的大小可能与int-s不同;您可能希望使用intptr_t),但这与代码没有多少共同之处。
如果您想要调用任意的任意签名函数,请考虑使用一些库,比如libFFI (当然这是特定于实现的)。
注意,位域是实现特定的,并且效率不高(就访问时间而言)。对于在台式机或笔记本电脑上运行的软件来说,它们几乎总是无用的。它们在实现特定的低级别嵌入式代码(例如洗衣机中的微控制器 )方面更有用,然后您应该知道您的实现(包括编译器)正在做什么。
顺便说一句,您的代码是错误的,因为lastfour包含一个char (通常是一个8位字节),所以它不能与4位位字段(bits12 .bits15)占据相同的位置;也许您应该用unsigned valfourbits : 4;等替换firstfour中的unsigned char value;。
要将一些动态类型的数据传递给某个函数,您可能需要一些有标记的联合。Glib GVariant型是一个真实的例子(您可能会深入到源代码中)。
如果您了解一些汇编程序,可以尝试查看编译器生成的汇编程序代码。如果使用GCC进行编译,请尝试使用gcc -Wall -fverbose-asm -O -S your-main.c编译程序,然后(使用编辑器或寻呼机)查找your-main.s中生成的汇编程序代码。
注意(假设您没有使用register关键字,它已经过时了)每个数据-variable或聚合字段或数组组件都是可寻址的(您可以使用一元前缀&操作符的地址),并且在实际中可以作为连续字节坐在内存中,并具有某种对齐约束。但是,位字段(和register变量)是一个例外。它们是不可寻址的,而且位字段通常位于特定于实现的可寻址内存区域中。
一般的经验规则是避免位字段。这个规则是有例外的,但是你应该首先了解更多关于C的知识。
https://stackoverflow.com/questions/29165588
复制相似问题