2013-06-22 1 views
1

Я работаю над побитовыми операциями для целых чисел без знака. Я хочу написать функцию left-circle-shift для типов uint8_t, uint16_t, ..., uint64_t.Безопасны ли указатели на пустоты?

Мое решение:

(void*) left_circular_shift(void* number, size_t size); 

Если размер 64, преобразовать аннулируются * в uint64_t и т.д., но многие программисты не использовать пустоты *. Должен ли я реализовать эту функцию для всех неподписанных целых типов?

+2

Макрос типового типа может быть полезным подходом. –

+0

Вы хотите преобразовать 'void *' в 'uint64_t' или' uint64_t * '? Это имеет большое значение. –

ответ

0

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

1

В вашем случае вы не можете использовать void *. Если у вас есть общая функция, которая принимает void *, вы не сможете измерить размер того, что у вас есть (как он знает, где заканчивается ваш номер?), Поэтому вы не сможете отбросить его.

Относительно того, что Void * является «безопасным»: причина, по которой вы, возможно, слышали, что она «небезопасна», состоит в том, что она является универсальным указателем не-типа, который требует, чтобы вы точно знали, какие данные вы используете (вам нужно отбросить его). Таким образом, он более подвержен неожиданным и странным ошибкам, если использовать их небрежно.

Простой способ сделать это - использовать одну функцию для каждого. Другой вариант, как и другие люди, предлагает общий макрос, который может вас заинтересовать: http://www.ibm.com/developerworks/linux/library/l-gcc-hacks/index.html

1

В C++ имеет смысл реализовать эту функцию для всех неподписанных типов (сохраняя одно и то же имя функции). В C это невозможно, но вы можете создавать различные функции для всех типов, как left_circular_shift_64 т.д.

Если вы хотите сохранить свой интерфейс, то вы должны преобразовать void* в uint64_t* (не uint64_t). Также может быть полезно указать size в байтах, а не в битах. Тогда может быть использована следующая конструкция:

uint64_t value; 
left_circular_shift(&value, sizeof(value)); 

Это поможет, если, например, тип value изменяется на uint32_t.

Даже если эта опция действительна и «безопасна», я бы предложил использовать различные функции для каждого типа. Некоторые причины, чтобы поддержать этот вариант:

  • Это невозможно передать о неверных данных функции, например, float, struct или объект.
  • Невозможно передать неправильную размер функции, например. 62. Таким образом, вам не нужно изобретать, что делать, если функция получает странный ввод.
  • Вам не нужно поддерживать оба параметра (указатель и размер), что уменьшает вероятность ошибок.
  • В C++ могут возникнуть проблемы с литьем void* в некоторые сложные типы (например, классы с множественным наследованием), если вам нужно реализовать операцию переключения для таких типов.
1

Нет оснований использовать тип указателя вообще для такой основной задачи. Используйте

inline 
uintmax_t left_circular_shift(uintmax_t number, size_t size) { 
    return /* your implementation goes here */ 
} 

в заголовочном файле, и

extern inline uintmax_t left_circular_shift(uintmax_t number, size_t size); 

в одном .c файле.

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