Можно ли использовать memset для многобайтовых типов и ненулевых значений

Я пытаюсь инициализировать массив ненулевым значением:

BYTE byteArray[50];
memset(byteArray, 20, sizeof(byteArray));   // Works fine

int intArray[50];
memset(intArray, 20, sizeof(intArray));     // Does not work

На данный момент я просто вручную инициализирую массив:

// Initialise array manually
for (int pos = 0; pos < 50; pos++)
    intArray[pos] = 20;

Я понимаю, что memset устанавливает каждый байт в диапазоне памяти, поэтому это не может работать так, как мне нужно для многобайтовых типов (за исключением особого случая, когда запрошенное значение равно 0). Есть ли способ принудить memset к ненулевым значениям, используя многобайтовые типы, или, возможно, есть альтернативная библиотечная функция?


person AlainD    schedule 03.03.2017    source источник
comment
В C++ вы можете использовать std::fill_n вместо memset.   -  person Bo Persson    schedule 03.03.2017
comment
По какой-то конкретной причине вы пометили это как C, так и C++?   -  person Lundin    schedule 03.03.2017
comment
@Lundin: это C++ DLL (с ​​использованием Visual Studio). Ничего особо объектно-ориентированного не делается, поэтому много кода в стиле C. Предлагаемый std::fill_n отлично работает.   -  person AlainD    schedule 03.03.2017
comment
@BoPersson: Отлично, спасибо! Просто нужно #include <algorithm>.   -  person AlainD    schedule 03.03.2017
comment
Помимо многобайтового значения 0 вы также можете установить многобайтовое значение со знаком -1 (если закодировано как 0xFFFFFFFF) или значение без знака UINT_MAX, оба из которых могут быть полезны для инициализации массива.   -  person Weather Vane    schedule 03.03.2017
comment
Если значение должно состоять из повторяющихся частей (например, для всех значений массива типа uint16_t должно быть установлено значение 0x2020), то да, в противном случае (например, 0x0020), то только для крайних случаев, как упоминает флюгер.   -  person Toby    schedule 03.03.2017
comment
В свете вышеприведенного комментария о том, что это для C++ DLL, я снова добавил тег [C++], тем более что автор уже сказал, что std::fill_n является приемлемым решением.   -  person JeremyP    schedule 03.03.2017
comment
@JeremyP: Да, верно, std::fill_n работает хорошо. Возможно, тот, кто удалил тег [C++], сделал это, потому что memset — это библиотечная функция C, но это было немного переусердствовало, поскольку вопрос относится к семейству C/C++. Спасибо.   -  person AlainD    schedule 03.03.2017
comment
функция memset() работает с байтами, она ничего не знает ни о каком другом объекте, например int   -  person user3629249    schedule 05.03.2017


Ответы (3)


Есть ли способ заставить memset использовать ненулевые значения, используя многобайтовые типы?

No.

или, возможно, есть эквивалентная библиотечная функция C?

Не то, что я знаю о. Вместо этого вы можете использовать простой цикл.

Но поскольку вы отметили C++, в этой стандартной библиотеке есть соответствующая функция: std::fill или std::fill_n.

PS. memset работает не только с 0. Он также работает со всеми числами с одинаково повторяющимся шаблоном байтов. Например, ~0.

person eerorika    schedule 03.03.2017

В C вы можете инициализировать массив одним значением следующим образом:

#define ONE(n)   (n),
#define FIVE(n)  ONE(n) ONE(n) ONE(n) ONE(n) ONE(n)
#define TEN(n)   FIVE(n) FIVE(n)
#define FIFTY(n) TEN(n) TEN(n) TEN(n) TEN(n) TEN(n)

const int intArray [50] = { FIFTY(20) };

Или, если вы хотите назначить его во время выполнения:

int intArray [50];
...
memcpy( intArray, &(int[50]){FIFTY(20)}, sizeof(intArray) );

Альтернативная переменная, которую легче поддерживать:

#define I1(n)  (n),
#define I2(n)  I1(n) I1(n)
#define I3(n)  I1(n) I1(n) I1(n)
#define I5(n)  I1(n) I1(n) I1(n) I1(n) I1(n)
#define I10(n) I5(n) I5(n)
#define I50(n) I10(n) I10(n) I10(n) I10(n) I10(n)

#define INIT_FILL_ARRAY(n, val) I##n(val)

int main (void)
{
  const int intArray[] = 
  { 
    INIT_FILL_ARRAY(5, 20) 
    INIT_FILL_ARRAY(3, 10) 
    INIT_FILL_ARRAY(2, 123)
  };

  for(size_t i=0; i<sizeof intArray/sizeof *intArray; i++)
  {
    printf("%d %d\n", i, intArray[i]);
  }
}

Выход:

0 20
1 20
2 20
3 20
4 20
5 10
6 10
7 10
8 123
9 123
person Lundin    schedule 03.03.2017
comment
@AlainD Не совсем, это обычная практика. Я разместил переменную альтернативу. Теперь все, что вам нужно сделать, это добавить макросы, когда вы обнаружите, что они отсутствуют. - person Lundin; 03.03.2017

Очень простой способ инициализации массива:

int myArray[50] = {20};

который инициализирует весь массив значений int до 20

person user3629249    schedule 05.03.2017
comment
Это только устанавливает первый элемент равным 20... остальные - нули. Этот ответ содержит более подробную информацию stackoverflow.com/questions/1065774/. std::fill_n делает то, что мне нужно. - person AlainD; 06.03.2017