Ios 目标C中的比特掩蔽

Ios 目标C中的比特掩蔽,ios,objective-c,bit-manipulation,Ios,Objective C,Bit Manipulation,我想学点掩蔽术。据我所知,它是指将特定类型的二进制值存储到一个变量中 如果上述假设是真的,我想我可以这样做: typedef NSUInteger Traits; enum { TraitsCharacterHonest = 0, TraitsCharacterOptimistic = 1, TraitsCharacterPolite = 4, TraitsCharacterDevious = 8, TraitsPh

我想学点掩蔽术。据我所知,它是指将特定类型的二进制值存储到一个变量中

如果上述假设是真的,我想我可以这样做:

typedef NSUInteger Traits;

enum
{
    TraitsCharacterHonest       = 0,
    TraitsCharacterOptimistic   = 1,
    TraitsCharacterPolite       = 4,
    TraitsCharacterDevious      = 8,
    TraitsPhysicalTall          = 16,
    TraitsPhysicalBeautiful     = 32,
    TraitsPhysicalFat           = 64,
    TraitsPhysicalBigEyes       = 128,
    TraitsPhysicalRedHair       = 256, 
};

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits    *traits;

@end
Person *john = [[Person alloc] init];

//here code that assigns john three traits: TraitsCharacterHonest,      
//TraitsCharacterOptimistic and TraitsPhysicalBeautiful.
typedef enum
{
    TraitsCharacterHonest       = 1 << 0,
    TraitsCharacterOptimistic   = 1 << 1,
    TraitsCharacterPolite       = 1 << 2,
    TraitsCharacterDevious      = 1 << 3,
    TraitsPhysicalTall          = 1 << 4,
    TraitsPhysicalBeautiful     = 1 << 5,
    TraitsPhysicalFat           = 1 << 6,
    TraitsPhysicalBigEyes       = 1 << 7,
    TraitsPhysicalRedHair       = 1 << 8
} Traits;

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits     traits;

@end
Person *john = [[Person alloc] init];

john.traits = TraitsCharacterHonest | TraitsCharacterOptimistic | TraitsPhysicalBeautiful;
NSMutableString *result = [NSMutableString string];

if (self.traits & TraitsCharacterHonest)
{
    [result appendString: @"Honest, "];
}
if (self.traits & TraitsCharacterOptimistic)
{
    [result appendString: @"Optimistic, "];
}
if (self.traits & TraitsCharacterPolite)
{
    [result appendString: @"Polite, "];
}
// etc...
如果我理解正确的话

john.traits应该是100011,从右边和代表特定枚举值/特征的每个位置读取。0表示没有,1表示有


如果需要,请您提供语法方面的建议,并解释特定方面的内容好吗?

您在这里的主要问题是将
traits
设置为指针。放下指针,像在C中那样操作:

john.traits |= TraitsCharacterOptimistic | TraitsCharacterOptimistic | TraitsCharacterOptimistic;
记住,在Objective-C中,您只需要在几种情况下使用指针:

  • 当您处理实际对象时(源自
    NSObject
  • 当您需要通过引用(一个
    int*
    参数)将一个基元传递给一个函数以返回计数时,在这种情况下,您获取一个局部变量的地址,并且该指针不被函数保存
  • 当您需要一个基元类型数组时,在堆上动态分配(例如使用
    malloc
    &friends)
否则,只需使用堆栈分配的基本类型,因为您可以用它做很多事情。

首先更改:

...
typedef NSUInteger Traits;

enum
{
    TraitsCharacterHonest = 0, //cann't be a 0
    ...
};
...
@property (assign, nonatomic) Traits *traits; //you no need create a pointer to a primitive type
致:

对于分配,您应该执行以下操作:

john.traits |= TraitsCharacterHonest | TraitsCharacterDevious;
ObjC中的按位操作与
C
语言中的相同。
查看本教程

您可能遇到的一个问题是,使用位掩码指示集合中的成员资格可能会被基础数据类型中的位数所限制。例如,32位的无符号长字符串只能容纳32个不相交或不同的成员。如果您需要添加第33位,那么除非您使用64位无符号整数,否则您就不走运了

解决方法之一是使用字节数组。使用这种方法,您必须将位成员身份指定为两段数据,即字节偏移量和用于特定位的位掩码

我还看到人们使用字节数组作为单个成员,因此使用的不是一个位,而是整个字节。这可能会浪费内存,但也可能是因为它更灵活、更有用,而且浪费的内存量不是问题

使用字节数组来保存一组位,可以考虑使用一个无符号长来表示最低位字节是位掩码的集合的成员,其余的字节用作字节数组中的无符号3字节偏移量。然后,您将执行以下操作:

int getBitSet (unsigned char *bArray, unsigned long ulItem)
{
    unsigned long ulByteOffset = ((ulItem >> 8) & 0x00ffffff);
    unsigned char ucByteMask = (ulItem & 0x000000ff);

    return (*(bArray + ulByteOffset) & ucByteMask);
}

int setBitSet (unsigned char *bArray, unsigned long ulItem, unsigned long ulNewValue)
{
    unsigned char oldValue;
    unsigned long ulByteOffset = ((ulItem >> 8) & 0x00ffffff);
    unsigned char ucByteMask = (ulItem & 0x000000ff);

    oldValue = *(bArray + ulByteOffset) & ucByteMask;

    if (ulNewValue) {
        *(bArray + ulByteOffset) |= ucByteMask;  // set bit
    } else {
        *(bArray + ulByteOffset) &= ~ucByteMask;  // clear bit
    }

    return oldValue;
}

然后可以使用一组函数来获取和设置字节,也可以使用宏。使用C++,您可以为这个功能创建自己的类,并提供各种类型的逻辑操作,这样您就可以创建各种类型的集合,然后对集合执行逻辑运算。

< P>我建议更改一些事情:

  • 枚举值可以更改为左移。在我看来,这样写起来更容易一些

  • 您不需要将typedef转换为整数,您可以直接使用
    typedef enum
    声明枚举类型

  • 而且,正如其他人提到的,您的属性不应该是指向Traits类型的指针

我的代码如下所示:

typedef NSUInteger Traits;

enum
{
    TraitsCharacterHonest       = 0,
    TraitsCharacterOptimistic   = 1,
    TraitsCharacterPolite       = 4,
    TraitsCharacterDevious      = 8,
    TraitsPhysicalTall          = 16,
    TraitsPhysicalBeautiful     = 32,
    TraitsPhysicalFat           = 64,
    TraitsPhysicalBigEyes       = 128,
    TraitsPhysicalRedHair       = 256, 
};

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits    *traits;

@end
Person *john = [[Person alloc] init];

//here code that assigns john three traits: TraitsCharacterHonest,      
//TraitsCharacterOptimistic and TraitsPhysicalBeautiful.
typedef enum
{
    TraitsCharacterHonest       = 1 << 0,
    TraitsCharacterOptimistic   = 1 << 1,
    TraitsCharacterPolite       = 1 << 2,
    TraitsCharacterDevious      = 1 << 3,
    TraitsPhysicalTall          = 1 << 4,
    TraitsPhysicalBeautiful     = 1 << 5,
    TraitsPhysicalFat           = 1 << 6,
    TraitsPhysicalBigEyes       = 1 << 7,
    TraitsPhysicalRedHair       = 1 << 8
} Traits;

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits     traits;

@end
Person *john = [[Person alloc] init];

john.traits = TraitsCharacterHonest | TraitsCharacterOptimistic | TraitsPhysicalBeautiful;
NSMutableString *result = [NSMutableString string];

if (self.traits & TraitsCharacterHonest)
{
    [result appendString: @"Honest, "];
}
if (self.traits & TraitsCharacterOptimistic)
{
    [result appendString: @"Optimistic, "];
}
if (self.traits & TraitsCharacterPolite)
{
    [result appendString: @"Polite, "];
}
// etc...
然而,虽然位字段学习起来很有用,但调试起来却很麻烦。如果你想去打印 现在,您必须编写如下代码:

typedef NSUInteger Traits;

enum
{
    TraitsCharacterHonest       = 0,
    TraitsCharacterOptimistic   = 1,
    TraitsCharacterPolite       = 4,
    TraitsCharacterDevious      = 8,
    TraitsPhysicalTall          = 16,
    TraitsPhysicalBeautiful     = 32,
    TraitsPhysicalFat           = 64,
    TraitsPhysicalBigEyes       = 128,
    TraitsPhysicalRedHair       = 256, 
};

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits    *traits;

@end
Person *john = [[Person alloc] init];

//here code that assigns john three traits: TraitsCharacterHonest,      
//TraitsCharacterOptimistic and TraitsPhysicalBeautiful.
typedef enum
{
    TraitsCharacterHonest       = 1 << 0,
    TraitsCharacterOptimistic   = 1 << 1,
    TraitsCharacterPolite       = 1 << 2,
    TraitsCharacterDevious      = 1 << 3,
    TraitsPhysicalTall          = 1 << 4,
    TraitsPhysicalBeautiful     = 1 << 5,
    TraitsPhysicalFat           = 1 << 6,
    TraitsPhysicalBigEyes       = 1 << 7,
    TraitsPhysicalRedHair       = 1 << 8
} Traits;

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits     traits;

@end
Person *john = [[Person alloc] init];

john.traits = TraitsCharacterHonest | TraitsCharacterOptimistic | TraitsPhysicalBeautiful;
NSMutableString *result = [NSMutableString string];

if (self.traits & TraitsCharacterHonest)
{
    [result appendString: @"Honest, "];
}
if (self.traits & TraitsCharacterOptimistic)
{
    [result appendString: @"Optimistic, "];
}
if (self.traits & TraitsCharacterPolite)
{
    [result appendString: @"Polite, "];
}
// etc...
此外,删除特征等操作的语法令人困惑。您必须使用
&
和一个NOT ed常量

// remove 'Tall' trait
john.traits = john.traits & ~TraitsPhysicalTall
如果可以的话(性能也不是什么大问题),我更喜欢使用更高级的功能。可能是带有字符串常量的NSSet?e、 g

__unused static NSString *TraitsCharacterHonest = @"TraitsCharacterHonest";
__unused static NSString *TraitsCharacterOptimistic = @"TraitsCharacterOptimistic";
__unused static NSString *TraitsCharacterPolite = @"TraitsCharacterPolite";
// etc...

@interface Person : NSObject

@property (strong, nonatomic) NSString     *name;
@property (assign, nonatomic) NSMutableSet *traits;

@end
然后你可以做:

// adding
[john.traits addObject: TraitsCharacterHonest];
// checking
[john.traits containsObject: TraitsCharacterHonest];
// removing 
[john.traits removeObject: TraitsCharacterHonest];
typedef NS_OPTIONS(NSUInteger, Traits) {
    TraitsCharacterHonest,
    TraitsCharacterOptimistic,
    TraitsCharacterPolite,
    TraitsCharacterDevious,
    TraitsPhysicalTall,
    TraitsPhysicalBeautiful,
    TraitsPhysicalFat,
    TraitsPhysicalBigEyes,
    TraitsPhysicalRedHair
};
对我来说更有意义。更重要的是,你可以直接用打印机打印特征描述

NSLog(@"John's traits: %@", john.traits);

您将获得合理的输出。

在iOS 6或更高版本、Mac OS X 10.8或更高版本中

你可以做:

// adding
[john.traits addObject: TraitsCharacterHonest];
// checking
[john.traits containsObject: TraitsCharacterHonest];
// removing 
[john.traits removeObject: TraitsCharacterHonest];
typedef NS_OPTIONS(NSUInteger, Traits) {
    TraitsCharacterHonest,
    TraitsCharacterOptimistic,
    TraitsCharacterPolite,
    TraitsCharacterDevious,
    TraitsPhysicalTall,
    TraitsPhysicalBeautiful,
    TraitsPhysicalFat,
    TraitsPhysicalBigEyes,
    TraitsPhysicalRedHair
};
有关更多信息,请参阅假设:


1是否有意让
traitCharacter诚实
的数值为零?这里不能使用零,因为任何整数的
x&0==0
,也就是说,任何人都不会出现这种特征。在那个世界上没有诚实的人。悲哀的地方…就像普通的旧C一样——Objective-C中没有特殊的设施来提供一些有意义的值。这不是故意的,我没有意识到。当然,第一项的值必须为1。正确的顺序是2的幂,是吗?2to0、2 to1、2to2即1、2、4、8、16等。使用由十六进制常数组成的位掩码比使用十进制数容易得多。因此,1将是0x0001,2将是0x0002,16将是0x0010,256将是0x0100,等等。这使得位掩码更容易可视化。@Dirk,枚举时不要从零开始这一点很好。通常情况下,零将用于表示起点没有特征,然后您将为不同的特征添加各种位掩码。该基元数组不需要动态分配。@H2CO3当然不需要,这只是使用指向基元类型指针的一个示例。将其设为指针只是内存错误。当然,这是一个原始的值。这是一个非常笨拙的解决方案,如果你使用C++,那么一个<代码> STD::BITSET (或<代码> STD::向量< /代码>)在这里更具意义。我同意使用已经存在的通常是最好的。另一方面,如果它不存在,那么你必须构建一些东西。我提供了一个可以做什么而不是应该做什么的例子。问题是有人想学习位屏蔽操作,我能不能避免明确地将2的幂赋给枚举值?我已经看到了这个1是的,你可以使用这个语法1我需要为所有人或在fir之后这样做吗