首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函数指针和开关语句

函数指针和开关语句
EN

Code Review用户
提问于 2011-02-19 18:05:21
回答 2查看 4.7K关注 0票数 6

我觉得使用函数指针可以使开关语句更加优雅,也就是说,我希望在同一个开关语句中设置digestLength和指向函数的指针,而不是设置长度,声明结果数组,然后调用函数。

代码语言:javascript
复制
- (NSString *)hashWithDigestType:(NSStringDigestType)type {
    const char *s = [self UTF8String];
    int digestLength;

    switch (type) {
        case NSStringDigestTypeMD5:
            digestLength = CC_MD5_DIGEST_LENGTH;
            break;
        case NSStringDigestTypeSHA1:
            digestLength = CC_SHA1_DIGEST_LENGTH;
            break;
        case NSStringDigestTypeSHA512:
            digestLength = CC_SHA512_DIGEST_LENGTH;
            break;
    }

    unsigned char result[digestLength]; 

    switch (type) {
        case NSStringDigestTypeMD5:
            CC_MD5(s, strlen(s), result);
            break;
        case NSStringDigestTypeSHA1:
            CC_SHA1(s, strlen(s), result);
            break;
        case NSStringDigestTypeSHA512:
            CC_SHA512(s, strlen(s), result);
            break;
    }

    NSMutableString *digest = [NSMutableString stringWithCapacity:(digestLength * 2)];
    for (NSUInteger i = 0; i < digestLength; i++)
        [digest appendFormat:@"%02x",result[i]];

    return [NSString stringWithString:digest];
}
EN

回答 2

Code Review用户

发布于 2011-02-19 21:59:12

我不能用Objective编写代码,但是在C中,您可以创建一个结构类型来一步一步地获取信息。我不知道NSStringDigestTypeXXX值是方便地从0还是1严格编号的,所以我持悲观观点,认为它们不是。您可以简化下面的代码,如果它们是紧凑和小的。

代码语言:javascript
复制
struct Digestifier  // Declaration in a header (probably)
{
    int      hashtype;
    void   (*hash)(const char *source, size_t length, char *result);
    size_t   hashlen;
};
static const struct Digestifier digests[] =
{
    { NSStringDigestTypeSHA1,   CC_SHA1,   CC_SHA1_DIGEST_LENGTH   },
    { NSStringDigestTypeMD5,    CC_MD5,    CC_MD5_DIGEST_LENGTH    },
    { NSStringDigestTypeSHA512, CC_SHA512, CC_SHA512_DIGEST_LENGTH },
};
{ enum NUM_DIGESTS = sizeof(digests) / sizeof(digests[0]) };

然后,您可以为此编写一个查找函数:

代码语言:javascript
复制
const struct Digestifier *digest_lookup(int hashtype)
{
    for (i = 0; i < NUM_DIGESTS; i++)
    {
        if (digests[i].hashtype == hashtype)
            return &digests[i];
    }
    assert(i != NUM_DIGESTS);  // Or other error handling!
    return 0;
}

在你的工作中:

代码语言:javascript
复制
- (NSString *)hashWithDigestType:(NSStringDigestType)type {
    const char *s = [self UTF8String];
    const struct Digestifier *digest = digest_lookup(type);

    // Error check digest if digest_lookup() does not do it for you!
    unsigned char result[digest->hashlen];
    digest->hash(s, strlen(s), result);

    NSMutableString *digest = [NSMutableString stringWithCapacity:(digest->hashlen * 2)];
    for (NSUInteger i = 0; i < digestLength; i++)
        [digest appendFormat:@"%02x",result[i]];

    return [NSString stringWithString:digest];
}

请注意,您还可以将哈希函数调用编写为:

代码语言:javascript
复制
    (*digest->hash)(s, strlen(s), result);

对于我们中的一些老(标准前)C程序员来说,这可能会更清楚一些。

此外,如果Objective支持C99指定的初始化符号,则可以使digests[]数组的初始化程序更加健壮(并使hashtype成员变得多余,除非进行交叉检查):

代码语言:javascript
复制
static const struct Digestifier digests[] =
{
    [NSStringDigestTypeSHA1]   =
           { NSStringDigestTypeSHA1,   CC_SHA1,   CC_SHA1_DIGEST_LENGTH   },
    [NSStringDigestTypeMD5]    =
           { NSStringDigestTypeMD5,    CC_MD5,    CC_MD5_DIGEST_LENGTH    },
    [NSStringDigestTypeSHA512] =
           { NSStringDigestTypeSHA512, CC_SHA512, CC_SHA512_DIGEST_LENGTH },
};

无论枚举的哪个成员映射到0、1、2,此初始化器都正确地将三行放置在数组中。

使用NSStringDigestTypeXXX值为0、1、2的附加信息,您可以通过以下方法简化digest_lookup()函数:

  1. 确保digests数组中的行序列正确(0、1、2)。
  2. 从搜索循环更改为直接数组查找。
  3. 可能是断言这个值在控制之下。

为了下面的代码的目的,我假设NSStringDigestTypeMD5为0,NSStringDigestTypeSHA512为2,但名称的排序是任意的;只需选择相当于断言中的第一个名称为0和第二个名称为2的等效值。

代码语言:javascript
复制
const struct Digestifier *digest_lookup(NSStringDigestType hashtype)
{
    assert(hashtype >= NSStringDigestTypeMD5 &&
           hashtype <= NSStringDigestTypeSHA512);
    assert(digest[hashtype].hashtype == hashtype);
    return &digests[hashtype];
}

第一个断言确保值在范围内。第二个断言确保对表进行了正确的排序,并且您将返回您期望的条目。

票数 4
EN

Code Review用户

发布于 2011-02-20 04:26:03

这是2美分左右。

  1. 您不应该使用以NS开头的标识符,因为此前缀仅为苹果保留。事实上,苹果最近开始完全不鼓励使用两个或三个字母的前缀。
  2. performSelector:digestMethods类型];考虑将每个散列计算作为单独的方法来实现;只需使用选择器而不是函数指针:- (NSString *) hashWithDigestType:(StringDigestType)类型{ SEL digestMethods[] ={ @selector(hashWithMD5)、@selector(hashWithSHA1)、@selector(hashWithSHA256) };返回[self 我不确定这种方法,但是 }考虑也验证type变量以及使用指定的初始值的可能性,这样就可以将枚举值直接映射到适当的选择器。
票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档