Указатели на функции и Switch


Я чувствую, как я могу сделать мой переключатель отчетности более элегантным с функцией указателя, т. е. я хочу установить digestLength и указатель на функцию, в то же Switch оператор вместо того, чтобы устанавливать длину, объявляя результат выбора, то вызов функции.

- (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];
}


3774
5
задан 19 февраля 2011 в 06:02 Источник Поделиться
Комментарии
2 ответа

Я не могу написать код в Objective-C, но в C, вы могли бы создать себе тип структуры, чтобы получить информацию в один ход. Я не знаю, являются ли значения NSStringDigestTypeXXX удобно, компактно, пронумерованных от 0 или 1, поэтому я беру пессимистический взгляд, что их нет. Вы можете упростить код, приведенный ниже, если они компактны и малы.

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]) };

Тогда можно написать функцию поиска для этого:

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;
}

И в вашу функцию:

- (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];
}


Обратите внимание, что вы также можете написать хэш-вызов функции как:

    (*digest->hash)(s, strlen(s), result);

Для некоторых из нас старая школа (предварительный стандарт) C программистов, который, возможно, будет понятнее.

Также, если цель-C не поддерживает С99 места инициализатор нотации, вы могли бы сделать инициализатор сборники[] массива более прочная (и сделать hashtype члена лишними за исключением перекрестной проверки):

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. Сделать строк в сборниках массива в правильном (0, 1, 2) последовательности.

  2. Меняется от цикла поиска прямой подстановки массива.

  3. Наверное, утверждая, что ценность находится под контролем.

Для целей указанных ниже код, я предполагаю, что NSStringDigestTypeMD5 0 и NSStringDigestTypeSHA512 равен 2, а порядок имен произвольный; просто выберите эквивалент для 0 имя в assert и 2 для второго.

const struct Digestifier *digest_lookup(NSStringDigestType hashtype)
{
assert(hashtype >= NSStringDigestTypeMD5 &&
hashtype <= NSStringDigestTypeSHA512);
assert(digest[hashtype].hashtype == hashtype);
return &digests[hashtype];
}

Первое утверждение означает, что значение находится в диапазоне. Второе утверждение гарантирует, что таблица является надлежащей последовательности, и вы получаете обратно свою ожидать.

3
ответ дан 19 февраля 2011 в 09:02 Источник Поделиться

Вот около 2 центов.


  1. Вы никогда не должны использовать идентификаторы, начинающиеся с НС, так как эта приставка предназначена только для Apple. В самом деле, в последнее время Apple начала обескураживает использование двух - или трехбуквенных префиксов полностью.

  2. [Я не уверен, что об этом подходе, но рассмотреть возможность реализации каждого вычисления хэш-в качестве отдельных методов; и просто с помощью селекторов вместо указателей на функции:

    - (NSString *) hashWithDigestType:(StringDigestType) type
    {
    SEL digestMethods[] = {
    @selector(hashWithMD5),
    @selector(hashWithSHA1),
    @selector(hashWithSHA256)
    };

    return [self performSelector:digestMethods[type]];
    }

    Рассмотрим также проверка типа переменной и возможность использования места initialisers, так что вы можете напрямую сопоставить значения перечислений в соответствующие селекторы.


3
ответ дан 20 февраля 2011 в 04:02 Источник Поделиться