C: cast int to size_t

Каков правильный способ конвертировать/отличать int до size_t в C99 на обеих 32-битных и 64-битных Linux-платформах?

Пример:

int hash(void * key) {
    //...
}

int main (int argc, char * argv[]) {
    size_t size = 10;
    void * items[size];
    //...
    void * key = ...;
    // Is this the right way to convert the returned int from the hash function
    // to a size_t?
    size_t key_index = (size_t)hash(key) % size;
    void * item = items[key_index];
}

Ответ 1

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

Лично мне не нравится видеть трансляции, потому что:

  • Они уродливые визуальные помехи, и
  • Они предлагают мне, чтобы тот, кто написал код, получал предупреждения о типах и бросал броски, чтобы заткнуть компилятор, не понимая причины предупреждений.

Конечно, если вы включите некоторые ультраприборные уровни предупреждения, ваши неявные преобразования могут вызвать множество предупреждений, даже если они верны...

Ответ 2

size_t key_index = (size_t)hash(key) % size;

в порядке. Вам даже не нужен бросок:

size_t key_index = hash(key) % size;

делает то же самое.

Ответ 3

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

если hash() должен возвращать индекс в массив, он должен также вернуть size_t. Так как это не так, вы можете получить странные эффекты, если key_index больше, чем INT_MAX.

Я бы сказал, что size, hash(), key_index должны быть одного типа, возможно, size_t, например:

size_t hash(void * key) {
    //...
}

int main (int argc, char * argv[]) {
    size_t size = 10;
    void * items[size];
    //...
    void * key = ...;

    size_t key_index = hash(key) % size;
    void * item = items[key_index];
}