Я читаю об инициализированных значениях по умолчанию массива /struct и задаю этот вопрос:
является memset(&mystruct, 0, sizeof mystruct)
таким же, как mystruct = { 0 };
?
Если это не так, какая разница?
Я читаю об инициализированных значениях по умолчанию массива /struct и задаю этот вопрос:
является memset(&mystruct, 0, sizeof mystruct)
таким же, как mystruct = { 0 };
?
Если это не так, какая разница?
- memset (&l; mystruct, 0, sizeof mystruct), такой же, как mystruct = {0};?
Нет.
memset(&mystruct, 0, sizeof mystruct) ;
... сообщит компилятору о вызове функции, которая, как мы ожидаем, установит во время выполнения данные в mystruct к нулю.
mystruct = { 0 };
... установит, что компилятор сам устанавливает данные в ноль, что означает:
Обратите внимание, что возможно компилятор может оптимизировать memset в команде времени компиляции (как замена первой версии второй версией), но я не стал бы полагаться на котором memset
является функцией из библиотеки времени выполнения, а не на каком-либо внутреннем языке языка ( Я не являюсь автором/автором языка компилятора, хотя).
Исходя из С++, моя собственная точка зрения заключается в том, что чем больше вы можете сделать при компиляции, тем больше компилятор знает во время компиляции, прежде чем выполнение даже начнется, тем лучше: он позволяет компилятору оптимизировать код и/или генерировать предупреждения/ошибки.
В текущем случае использование нотации mystruct = { 0 };
для инициализации a struct
всегда безопаснее, чем использование memset, потому что очень просто very легко записать неправильную вещь в C с помощью memset
без жалобы компилятора.
В приведенных ниже примерах показано, что код легко выполняет нечто иное, чем он выглядит:
// only the 1st byte will be set to 0
memset(&mystruct, 0, sizeof(char)) ;
// will probably overrun the data, possibly corrupting
// the data around it, and you hope, crashing the process.
memset(&mystruct, 0, sizeof(myLARGEstruct)) ;
// will NOT set the data to 257. Instead it will truncate the
// integer and set each byte to 1
memset(&mystruct, 257, sizeof(mystruct)) ;
// will set each byte to the value of sizeof(mystruct) modulo 256
memset(&mystruct, sizeof(mystruct), 0) ;
// will work. Always.
mystruct = { 0 } ;
Это полностью педантичный ответ, но учитывая, что внутреннее представление нулевого указателя не гарантируется 0
, поведение memset
по сравнению с инициализацией скобки будет отличаться (memset
будет делать не то, что нужно), Тем не менее, я никогда не слышал о реализации, которая взяла на себя эту свободу, чтобы иметь не все 0 бит шаблона для нулевого.
Теоретически существует разница. Инициализатору не требуется инициализировать заполнение, если в mystruct
есть некоторые.
Например:
int main(void)
{
struct mystruct {
char a;
int what;
} s = {0};
}
Может содержать:
00 xx yy zz 00 00 00 00
где xxyy и zz undefined байты, где в стеке.
Компилятору разрешено это делать.
Это сказало, практически на практике, я еще не столкнулся с компилятором, который это сделал. Большинство разумных реализаций будут семантически обрабатывать этот случай, как memset
.
memset(&mystruct, 0, sizeof mystruct);
- это утверждение. Он может быть выполнен в любое время, когда отображается mystruct
, а не только в том месте, где оно определено.
mystruct = { 0 };
на самом деле является синтаксической ошибкой; { 0 }
не является допустимым выражением.
(я буду считать, что mystruct
является объектом типа struct foo
.)
То, о чем вы, наверное, думаете:
struct foo mystruct = { 0 };
где { 0 }
- инициализатор.
Если ваш компилятор поддерживает его, вы также можете написать:
mystruct = (struct foo){ 0 };
где (struct foo){ 0 }
- составной литерал. Смешанные литералы были введены в C99; некоторые компиляторы C, особенно Microsoft, вероятно, не поддерживают его. (Обратите внимание, что (struct foo)
не является оператором трансляции, он похож на один, но не сопровождается выражением или именем типа в скобках. Это отличная синтаксическая конструкция.)
Если ваш компилятор не поддерживает сложные литералы, вы можете обойти его, объявив константу:
const struct foo foo_zero = { 0 };
struct foo mystruct;
/* ... */
mystruct = foo_zero;
Итак, как они отличаются синтаксисом и в том, где вы можете их использовать. Существуют также семантические различия.
Вызов memset
устанавливает все байты, которые составляют представление mystruct
ко всем нулям. Это очень низкоуровневая операция.
С другой стороны, инициализатор:
struct foo mystruct = { 0 };
устанавливает первый скалярный подкомпонент mystruct
в 0 и устанавливает все остальные подкомпоненты, как если бы они были инициализированы как статические объекты, т.е. к 0. (Было бы неплохо, если бы был синтаксис более чистого struct foo mystruct = { };
делайте то же самое, но нет.)
Дело в том, что настройка чего-то на 0
не обязательно такая же, как установка его представления на все бит-ноль. Значение 0
преобразуется в соответствующий тип для каждого скалярного подкомпонента.
Для целых чисел язык гарантирует, что all-bits-zero является представлением 0
(но не обязательно единственным представлением 0
). Очень вероятно, что установка целого числа в 0
установит его на все биты-ноль, но вполне возможно, что он может установить его в другое представление 0
. На практике это произойдет только с преднамеренно извращенным компилятором.
Для указателей большинство реализаций представляют собой нулевые указатели как все-биты-ноль, но язык не гарантирует этого, и были реалии реального мира, которые используют некоторое другое представление. (Например, использование чего-то типа "все-бит-1" может облегчить обнаружение нулевых указателей во время выполнения.) И представление может отличаться для разных типов указателей. См. Раздел 5 comp.lang.c FAQ.
Аналогично, для типов с плавающей точкой большинство реализаций представляют 0.0
как all-bits-zero, но языковой стандарт не гарантирует его.
Возможно, вам удастся списать код, предполагающий, что вызов memset
установит все подкомпоненты в ноль, но такой код не является строго переносимым - и Murphy Law подразумевает, что предположение не удастся в самый неудобный возможный момент, возможно, при переносе кода в важную новую систему.