Bry*_*yan 4 c cocoa enums objective-c bitmask
我正在使用NS_OPTIONS宏来创建一个位掩码.我已经为它分配了一种类型,NSInteger因为我正在构建一个64位平台,这应该给我总共63个"槽"(64位少一位用于签名).
这是枚举:
typedef NS_OPTIONS(NSInteger, LPSVGOPlugin) {
LPSVGOPluginNone = 0,
LPSVGOPluginCleanupAttrs = 1 << 0,
LPSVGOPluginRemoveDoctype = 1 << 1,
LPSVGOPluginRemoveXMLProcInst = 1 << 2,
LPSVGOPluginRemoveComments = 1 << 3,
LPSVGOPluginRemoveMetadata = 1 << 4,
LPSVGOPluginRemoveTitle = 1 << 5,
LPSVGOPluginRemoveDesc = 1 << 6,
LPSVGOPluginRemoveUselessDefs = 1 << 7,
LPSVGOPluginRemoveEditorsNSData = 1 << 8,
LPSVGOPluginRemoveEmptyAttrs = 1 << 9,
LPSVGOPluginRemoveHiddenElems = 1 << 10,
LPSVGOPluginRemoveEmptyText = 1 << 11,
LPSVGOPluginRemoveEmptyContainers = 1 << 12,
LPSVGOPluginRemoveViewBox = 1 << 13,
LPSVGOPluginCleanupEnableBackground = 1 << 14,
LPSVGOPluginMinifyStyles = 1 << 15,
LPSVGOPluginConvertStyleToAttrs = 1 << 16,
LPSVGOPluginConvertColors = 1 << 17,
LPSVGOPluginConvertPathData = 1 << 18,
LPSVGOPluginConvertTransform = 1 << 19,
LPSVGOPluginRemoveUnknownsAndDefaults = 1 << 20,
LPSVGOPluginRemoveNonInheritableGroupAttrs = 1 << 21,
LPSVGOPluginRemoveUselessStrokeAndFill = 1 << 22,
LPSVGOPluginRemoveUnusedNS = 1 << 23,
LPSVGOPluginCleanupIDs = 1 << 24,
LPSVGOPluginCleanupNumericValues = 1 << 25,
LPSVGOPluginMoveElemsAttrsToGroup = 1 << 26,
LPSVGOPluginMoveGroupAttrsToElems = 1 << 27,
LPSVGOPluginCollapseGroups = 1 << 28,
LPSVGOPluginRemoveRasterImages = 1 << 29,
LPSVGOPluginMergePaths = 1 << 30,
LPSVGOPluginConvertShapeToPath = 1 << 31,
LPSVGOPluginSortAttrs = 1 << 32,
LPSVGOPluginTransformsWithOnePath = 1 << 33,
LPSVGOPluginRemoveDimensions = 1 << 34,
LPSVGOPluginRemoveAttrs = 1 << 35,
LPSVGOPluginAddClassesToSVGElement = 1 << 36,
LPSVGOPluginRemoveStyleElement = 1 << 37
};
Run Code Online (Sandbox Code Playgroud)
最高值是左移37位,远低于我应该可用的63位.
我从该枚举创建一个掩码,如下所示:
LPSVGOPlugin defaultPluginMask = LPSVGOPluginNone;
defaultPluginMask = (LPSVGOPluginCleanupAttrs
|LPSVGOPluginRemoveDoctype
|LPSVGOPluginRemoveXMLProcInst
|LPSVGOPluginRemoveComments
|LPSVGOPluginRemoveMetadata
|LPSVGOPluginRemoveDesc
|LPSVGOPluginRemoveUselessDefs
|LPSVGOPluginRemoveEditorsNSData
|LPSVGOPluginRemoveEmptyAttrs
|LPSVGOPluginRemoveHiddenElems
|LPSVGOPluginRemoveEmptyText
|LPSVGOPluginRemoveEmptyContainers
|LPSVGOPluginCleanupEnableBackground
|LPSVGOPluginMinifyStyles
|LPSVGOPluginConvertStyleToAttrs
|LPSVGOPluginConvertColors
|LPSVGOPluginConvertPathData
|LPSVGOPluginConvertTransform
|LPSVGOPluginRemoveUnknownsAndDefaults
|LPSVGOPluginRemoveNonInheritableGroupAttrs
|LPSVGOPluginRemoveUselessStrokeAndFill
|LPSVGOPluginRemoveUnusedNS
|LPSVGOPluginCleanupIDs
|LPSVGOPluginCleanupNumericValues
|LPSVGOPluginMoveElemsAttrsToGroup
|LPSVGOPluginMoveGroupAttrsToElems
|LPSVGOPluginCollapseGroups
|LPSVGOPluginMergePaths
|LPSVGOPluginConvertShapeToPath
);
Run Code Online (Sandbox Code Playgroud)
当我记录defaultPluginMask使用此值时:
NSLog(@"maskValue: %li", (long)defaultPluginMask);
Run Code Online (Sandbox Code Playgroud)
结果是-536879137.一旦我从掩码中删除了最后一个掩码LPSVGOPluginConvertShapeToPathadd (),我得到一个正值:1610604511
重要的LPSVGOPluginConvertShapeToPath是,左移31位,这将是32位NSInteger中的最大位位置.但是如果我用它sizeof()来记录大小defaultPluginMask,它会报告为8个字节,这意味着它应该是64位.
我有点(哈!)困惑.我做了一个我没看到的基本错误吗?
对于long数据类型,C标准规定,最小范围要求是从-2147483648到2147483647,即,使用32 bits,包括符号位.
即使编译64 bits平台,也不能保证long变量将被表示64 bits.应确保使用最少64 bits的存储空间long long.正如@Olaf建议的那样,为了精确指定存储大小,stdint.h可以使用类型(例如int64_t).
但是上面的观察结果似乎并不是你问题的根源(如果NSInteger和long大小> = 8字节).
问题是要移位的值1是一个整数文字,它适合32位并且将被存储(如果它不适合32位,例如5亿,它将存储在64位).并且1 << 31将是一个带符号的32位整数,其中1位于符号位置,因此为负数.如果稍后将其分配给64位有符号整数变量,则将对符号位进行扩展(二进制补码表示).
这可以从您的案例中观察到的值中看出,它们以64位十六进制表示为:
-536879137 => ffffffffdfffdfdf - when 1 << 31 is present
1610604511 => 5fffdfdf - when 1 << 31 is removed
Run Code Online (Sandbox Code Playgroud)
下面我做了一个小实验,看看在这个"边界"附近会发生什么(应该注意的是,从1 << 32并获得的值1 << 33是未定义的行为 - 转移到存储大小,在其他平台上可能会产生相同的结果1 << 0和1 << 1).
printf("%d %d %d %d\n", sizeof(int), sizeof(long), sizeof(long long), sizeof(void*));
// Prints: 4 4 8 8, running on an Windows 64-bit, compiled with gcc from MinGW
long long a[9] = {
1 << 30, // 1073741824 40000000
1LL << 30, // 1073741824 40000000
1 << 31, // -2147483648 ffffffff80000000
1LL << 31, // 2147483648 80000000
1 << 32, // 0 0
1LL << 32, // 4294967296 100000000
1 << 33, // 0 0
1LL << 33, // 8589934592 200000000
5000000000,// 5000000000 12a05f200
};
// Prints of this loop are in the comments above
for (int i = 0; i < 9; i++)
printf("%12lli %16llx\n", a[i], a[i]);
Run Code Online (Sandbox Code Playgroud)
解决方案:如果要在结果不适合该文字的存储大小的操作中直接使用整数文字,则必须以下列后缀为:
u/ Ufor unsigned(如果需要)
l/ L为long
ll/ LL为long long
可以通过将LL后缀应用于这些元素来解决问题中的问题:
LPSVGOPluginConvertShapeToPath = 1LL << 31,
LPSVGOPluginSortAttrs = 1LL << 32,
LPSVGOPluginTransformsWithOnePath = 1LL << 33,
LPSVGOPluginRemoveDimensions = 1LL << 34,
LPSVGOPluginRemoveAttrs = 1LL << 35,
LPSVGOPluginAddClassesToSVGElement = 1LL << 36,
LPSVGOPluginRemoveStyleElement = 1LL << 37
Run Code Online (Sandbox Code Playgroud)