64位NS_OPTIONS位掩码 [英] 64-bit NS_OPTIONS bitmask

查看:182
本文介绍了64位NS_OPTIONS位掩码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 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 for unsigned (如果需要)

  • u/U for unsigned (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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆