Функция memcpy()
отлично работает. Функции проверки границ C11 были введены как часть снижения вероятности дефектов переполнения буфера.
Документ N1967, Опыт работы в полевых условиях с Приложением K - Границы проверки интерфейсов , в разделе «Ненужное использование» есть следующее:
Распространенная ошибка, возникшая из-за того, что Microsoft осудила
стандартные функции [DEPR] в целях расширения принятия
API заключается в том, что каждый вызов стандартных функций обязательно
небезопасно и должно быть заменено одним на «более безопасный» API. В следствии,
Команды, ориентированные на безопасность, иногда наивно вступают в многомесячные проекты
переписать свой рабочий код и покорно заменить все экземпляры
«устаревшие» функции с соответствующими API. Это не только
приводит к ненужному оттоку и повышает риск внедрения новых ошибок
в правильный код, это также делает переписанный код менее эффективным.
Оператор sizeof
- это оператор времени компиляции, который означает, что вычисление размера выполняется с помощью любой информации, доступной компилятору во время компиляции. Вот почему использование оператора может быть проблематичным и источником ошибок времени выполнения при использовании с указателями и массивами. Повышение уровня предупреждения компилятора и использование инструмента статического анализа кода может помочь найти эти проблемные области.
Поскольку оператор sizeof
является оператором времени компиляции, вы ничего не можете сделать для ошибки или предупреждения компилятора, хотя ваш конкретный компилятор может иметь уровень предупреждения, который вы можете установить, который будет выполнять этот тип проверки.
То, что я сделал, - это наличие макроса препроцессора, который я могу использовать для проверки во время выполнения в отладочных сборках или специальных сборках выпуска, используемых при проверке, которые будут удалены при выполнении сборки выпуска для производства, чтобы снять накладные расходы на проверку .
Так что, если у вас есть источник, такой как:
uint8_t mybuffer[4];
float f;
memcpy(&f, mybuffer, sizeof(mybuffer));
будет иметь правильное количество байтов, потому что массив mybuffer[4]
вместе с его фактическим размером доступен для компилятора.
Однако я бы предпочел следующую модификацию, указав вместо этого размер цели для memcpy()
. Это гарантирует, что не будет переполнения буфера, даже если исходный размер неверен.
uint8_t mybuffer[4];
float f;
memcpy(&f, mybuffer, sizeof(f));
, где возникают проблемы с оператором sizeof
, когда компилятор не может определить размер массива или размер объекта, адрес которого указан в указателе. Использование его с объявлением массива аргументов функции также небезопасно.
Если у вас есть функция int xxx (int a[5])
, и в этой функции вы пытаетесь использовать оператор sizeof
, чтобы получить размер массива в байтах, вы, скорее всего, получите размер int *
.