我正在尝试执行以下操作,但NSValue
的创建方法返回nil
。
结构中的C位域是否不受支持?
struct MyThingType {
BOOL isActive:1;
uint count:7;
} myThing = {
.isActive = YES,
.count = 3,
};
NSValue *value = [NSValue valueWithBytes:&myThing objCType:@encode(struct MyThingType)];
// value is nil here
答案 0 :(得分:6)
首先,claptrap在他的评论中提出了一个非常好的观点:为什么要使用位域说明符(主要用于 进行微优化或在需要的地方手动添加填充位) ,然后将它全部包装在NSValue
的实例中
这就像买一座城堡,然后住在厨房里,没有把地毯弄出来......
我认为不是,快速通过苹果开发人员came up with this ......在涉及位字段时确实需要考虑几个问题。
我刚刚找到了this,其中解释了为什么位字段+ NSValue
并没有真正发挥得很好。
特别是在sizeof
结构导致NSValue
读取...中的数据的情况下,我们应该说不稳定的方式:
您创建的结构填充为8位。现在这些位可以读作2 int
或1 long
或者其他东西......从我在链接页面上看到的内容来看,这不是不可能发生的事情。
因此,基本上,当您使用位字段时,NSValue
无法确定实际类型。如果存在歧义,则假定为int(大多数情况下为宽度为4),并且发生在/溢出下,并且您手上有一团糟。
由于编译器仍然具有某些自由关于实际存储成员的位置,因此传递字符串化的typedef类型(objCType: @encode(struct YourStruct
)是不够的,因为那里由于编译器优化等原因,你很有可能无法理解实际的结构本身......
我建议你简单地删除位字段说明符,因为结构应该支持...至少,上次我尝试过,一个简单原始类型的结构工作得很好。
答案 1 :(得分:0)
你可以用工会来解决这个问题。只需将结构放入联合,其中另一个成员具有NSValue
支持的类型,并且其大小大于您的结构。在你的情况下,long
显而易见。
union _bitfield_word_union
{
yourstructuretype bitfield;
long plain;
};
通过使用在编译时计算大小的数组,可以使结构大小更加健壮。 (请记住,sizeof()
也是编译时运算符。)
char plain[(sizeof(yourstructuretype)/sizeof(char)];
然后你可以将带有位域的结构存储到union中并读出plain
成员。
union converter = { .bitfield = yourstructuretypevalue };
long plain = converter.plain;
将此值用于NSValue
实例创建。读出来你必须采取相反的方式。
我很确定通过C99的技术更正,这成为标准符合(称为类型惩罚),因为您可以期望通过另一个成员值({{1)读出成员的值(bitfield
)如果被读取的成员至少与正在写入的成员一样大,则定义并将其存储回来。 (plain
中可能存在未定义的位9-31 / 63,但您不必关心它。)但它符合现实世界。
肮脏的黑客?也许。有人可能称之为C99。但是,将位域与plain
结合使用听起来就像使用脏黑客一样。