64位NS_OPTIONS位掩码 [英] 64-bit NS_OPTIONS bitmask
问题描述
我使用 NS_OPTIONS
宏创建位掩码。我已经分配了一种类型的 NSInteger
,而且由于我正在64位平台上构建,所以应该给我总共63个插槽
I'm using the NS_OPTIONS
macro to create a bitmask. I've assigned it a type of NSInteger
and since I'm building on a 64-bit platform, that should give me a total of 63 "slots" to work with (64 bits less one bit for signed-ness).
这是枚举:
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
};
顶部值是左移37位,远低于我应该有的63位
The top value is left-shifted 37 bits, which is well below the 63 bits I should have available.
我从中创建一个面具枚举,像这样:
I create a mask from that enumeration, like this:
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
);
当我记录 defaultPluginMask
的值使用这个:
When I log the value of defaultPluginMask
using this:
NSLog(@"maskValue: %li", (long)defaultPluginMask);
结果是-536879137。一旦我从掩码中删除最后一个掩码添加( LPSVGOPluginConvertShapeToPath
),我得到一个正值:1610604511
The result is -536879137. As soon as I remove that last mask addition (LPSVGOPluginConvertShapeToPath
) from the mask, I get a positive value: 1610604511
批判性地, LPSVGOPluginConvertShapeToPath
是左移31位,这将是32位NSInteger中的最大位位置。但是如果我使用 sizeof()
来记录 defaultPluginMask
的大小,那么它会报告为8个字节,这意味着应该是64位。
Critically, LPSVGOPluginConvertShapeToPath
is left-shifted 31 bits, which would be the maximum bit position in a 32-bit NSInteger. But if I use sizeof()
to log the size of defaultPluginMask
, it reports it as 8 bytes, which means it should be 64 bits.
我有点(哈!)困惑。我没有看到基本错误吗?
I'm a bit (ha!) confused. Have I made a basic error I'm not seeing?
推荐答案
对于 long
数据类型,C标准规定最小范围需要从 -2147483648
到 2147483647
,即使用 32位
,包括符号位。
For long
data type, C standard specifies that the minimum range is required to be from -2147483648
to 2147483647
, i.e. using 32 bits
, including the sign bit.
即使编译一个 64位
平台,也不能保证 long
变量将在 64位
上表示。为了确保它具有最小的 64位
的存储空间,应使用 long long
。在@Olaf推荐下,要精确指定存储大小,可以使用 stdint.h
类型(例如 int64_t
)。
Even if compiling for a 64 bits
platform, it is not guaranteed that a long
variable will be represented on 64 bits
. To ensure that it will have minimum 64 bits
of storage, long long
should be used. As @Olaf recommended, to precisely specify the storage size, stdint.h
types could be used (e.g. int64_t
).
但是,上述观察似乎不是您的情况的问题的根源(如果 NSInteger
和 long
size> = 8 bytes)。
But the observations above doesn't seem to be the source of the issue in your case (if NSInteger
and long
sizes are >= 8 bytes).
问题是要移动的值 1
是一个适合32位的整数文字,将会如此存储(如果它不适合32位,例如5亿,则将存储在64位)。而 1 < 31
将是一个有符号的32位整数,其中1位在符号位置,所以为负数。而且如果以后将其分配给64位有符号整数变量,则符号位将被扩展(二进制补码表示)。
The issue is that the value to be shifted 1
is an integer literal that fits in 32 bits and will be stored as such (if it wouldn't fit in 32 bits, e.g. 5 billions, it would be stored on 64 bits). And 1 << 31
will be a signed 32 bit integer, with 1 exactly on the sign position, so a negative number. And if this is assigned later to a 64 bit signed integer variable, the sign bit will be extended (two's complement representation).
可以从观察到的值中看出您的情况,以64位十六进制表示为:
This can be seen from the values observed in your case, which are represented in hexadecimal on 64 bits as:
-536879137 => ffffffffdfffdfdf - when 1 << 31 is present
1610604511 => 5fffdfdf - when 1 << 31 is removed
下面我做了一个小实验,看看这个边框附近会发生什么应该注意的是,从 1 <<32
和 1 <<33
获得的值是未定义的行为 - 转移在其他平台上可能发生的存储大小,以给出与 1 <<0
和 1 < 1
)。
Below I've done a small experiment to see what happens near this "border" (it should be noted that values obtained from 1 << 32
and 1 << 33
are undefined behaviour - shifting over the storage size, which on other platforms may happen to give the same results as 1 << 0
and 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]);
解决方案:如果整数文字旨在直接用于操作其结果将不符合该文字的存储大小,则必须加上以下内容:
Solution: If an integer literal is intended to be directly used in operations whose results won't fit in the storage size of that literal, it have to be suffixed with:
-
u
/U
forunsigned
(如果需要)
u
/U
forunsigned
(if needed)
l
/ L
for long
ll
/ LL
for long long
可以通过将 LL
后缀应用于这些元素来解决问题:
The issue in the question may be solved by applying the LL
suffix to these elements:
LPSVGOPluginConvertShapeToPath = 1LL << 31,
LPSVGOPluginSortAttrs = 1LL << 32,
LPSVGOPluginTransformsWithOnePath = 1LL << 33,
LPSVGOPluginRemoveDimensions = 1LL << 34,
LPSVGOPluginRemoveAttrs = 1LL << 35,
LPSVGOPluginAddClassesToSVGElement = 1LL << 36,
LPSVGOPluginRemoveStyleElement = 1LL << 37
这篇关于64位NS_OPTIONS位掩码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!