【问题标题】:Objective-c: Why is strtol method used in this code I inherited?Objective-c:为什么我继承的这段代码中使用了strtol方法?
【发布时间】:2018-11-07 00:29:59
【问题描述】:

我最近继承了一些 Objective-C 代码,但对它实际上在做什么感到很困惑?

1) 我不明白为什么 char byte_chars[3] 会先填充“0”,然后填充 0?

2) 我不明白他们为什么将unsigned char 用于整个字节,但要花很长时间?

3) 我对 strtol 方法在这里做了什么有点困惑,它需要 3 个 byte_chars 字节(是十六进制),然后将它们转换为 long?

- (NSString *)starFromFlags:(NSString *)flags {
    unsigned char wholeByte; 
    char byte_chars[3];
    NSString *star = @"NO";

    byte_chars[0] = '0'; 
    byte_chars[1] = [flags characterAtIndex:1]; 
    byte_chars[2] = 0; 
    wholeByte = strtol(byte_chars, NULL, 16); 

    if (wholeByte & 0x01) star = @"YES";

    return star;
}

【问题讨论】:

    标签: c objective-c strtol


    【解决方案1】:

    到1:

    末尾的 0 是末尾的 '\0'(两个值都是零),表示“字符串到此结束”。你必须把它放在最后才能结束字符串。

    开头的“0”(字母 0)表示 strtol() 的八进制值(不是十六进制,即“0x”)。但正如 CRD 正确提到的(参见 cmets),它在此处被传递给 strtol() 的第三个参数覆盖。所以到这里为止,你有一个双字母字符串,第一个字符为 0,第二个字符为标志的十六进制表示。

    原因可能是,flags 包含一个从 '0' 到 'f'₁₆/'F'₁₆(0 到 15₁₀)的数字。

    到2:

    由于转换可能产生的值在 [0…15] 范围内,因此 long 值将具有此值之一。您可以将其存储在单个字节中,并且不需要整个 long。但是,strtol() 总是返回一个 long。

    至3:

    是的,它是从包含数字的字符串到数字的转换。 IE。 字符串“06”将被转换为数字6。

    【讨论】:

    • 哈哈。对不起。评论已删除。我的 0 有一条线穿过它,但我看到那只是在代码 sn-ps 中。
    • strtol() 在这里被用来解析一个十六进制数,第三个参数是16 覆盖以字符0 开头的文本,意思是八进制。所以标志是任何一个十六进制数字。
    【解决方案2】:

    Amin Negm-Awad 解释了代码的作用(对八进制略有混淆),但要回答您的问题:

    为什么我继承的这段代码中使用了strtol方法?

    我们只能猜测。

    字符串中的第二个字符似乎是用于(最多)4 个标志位的十六进制数字,该方法正在测试是否设置了这些标志位中的最低有效位。一种更简单的方法可能是:

    - (NSString *)starFromFlags:(NSString *)flags
    {
       unichar flag = [flags characterAtIndex:1];
    
       if (flag > 127 || !isxdigit(flag))  // check flag is in ASCII range and hex digit
          return @"INVALID";
       else
          return digittoint(flag) & 0x1 ? @"YES" : @"NO"; // check if flag is odd hex
    }
    

    isxdigit()digittoint() 是 C 库函数(就像 strtol()),请在终端中使用 man isxdigit 获取文档(除非您使用的是具有这些文档的旧版 Xcode,Apple无济于事地删除了最新版本中的文档)。第一个检查字符是否为十六进制数字,第二个返回等效的整数。 > 127 检查是对字符串中非“ASCII”字符的最小保护。

    注意:NSString(呈现为)作为 UTF-16 代码单元序列,因此characterAtIndex: 返回unichar(16 位类型),因此返回flag 的类型。但是,此代码无法正确处理 any unicode 字符串。如果您的字符串是“ASCII”,它将起作用。

    上面的函数实际上比原来做了更多的错误检查,如果你愿意减少错误检查,你可以使用:

    - (NSString *)starFromFlags:(NSString *)flags
    {
       return digittoint([flags characterAtIndex:1]) & 0x1 ? @"YES" : @"NO";
    }
    

    这将返回@"YES"当且仅当标志是一个十六进制数字并且它的LSB被设置,如果它不是一个十六进制数字或者LSB没有被设置它返回@"NO"。这是因为 digittoint() 如果其参数不是十六进制数字,则返回 0

    那么为什么最初的程序员使用strtol()?也许他们不知道digittoint()

    HTH

    【讨论】:

    • 我在我的 ISO/IEC 9899:2011 副本中找不到 digittoint。它真的是一个 C 标准库函数吗?似乎是一些 BSD 扩展。
    • @Gerhardh - 至少从 2004 开始,它是 Mac 上的 C 库函数 - 根据该参考文献末尾的注释,当时它不在 C 标准中,我没有检查更新的标准。如果您希望坚持使用避免非标准化函数的代码,有很多方法可以进行转换,请参阅Convert single Character (hex number) to Integer in C 了解简单和巧妙的方法。
    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多