Подтвердить что ты не робот

Memcpy(), каково должно быть значение параметра размера?

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

Каковы плюсы и минусы следующих двух альтернатив параметра размера для memcpy()?

memcpy(dst, src, ARRAY_LENGTH*sizeof(int));

или

memcpy(dst, src, sizeof(dst));

Будет ли работать второй вариант? Независимо от содержания?

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

Спасибо

4b9b3361

Ответ 1

Пока dst объявлен как массив с размером, sizeof вернет размер этого массива в байтах:

int dst[ARRAY_LENGTH];

memcpy( dst, src, sizeof(dst) ); // Good, sizeof(dst) returns sizeof(int) * ARRAY_LENGTH

Если dst просто является указателем на первый элемент такого массива (который является тем же самым типом, что и сам массив), он не будет работать:

int buffer[ARRAY_LENGTH];
int* dst = &buffer[0];

memcpy( dst, src, sizeof(dst) ); // Bad, sizeof(dst) returns sizeof(int*)

Ответ 2

sizeof(dst) является правильным, только если dst - это массив, размер которого известен во время компиляции: например, int arr[ARRAY_LENGTH] или массив переменной длины C99; в противном случае он возвращает размер указателя, а не длину целевого массива.

Чтобы избежать ошибки в будущем, будьте последовательны и предпочитаете первую форму: размер типа * длина.

Ответ 3

Если и когда у вас есть массив (реальный), вы можете использовать трюк sizeof(array), но обратите внимание, что если вы реорганизуете код и нажимаете его где-нибудь, где массив распался на указатель (или если память была изначально выделенное в указателе (malloc/new), вам нужно будет передать известный размер.

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

template <typename T, int N>
inline int array_memory_size( T (&a)[N] ) { return sizeof a; }

Таким образом:

int main() {
   int array[10];
   int *ptr = array;
   int orig[10] = { 0 };
   memcpy( array, orig, array_memory_size(array) ); // ok
   //memcpy( ptr, orig, array_memory_size(ptr) ); // compilation error
}

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

Ответ 4

Будет ли работать второй вариант? Независимо от содержания?

Второй вариант работает, только если вы добавили обратно отсутствующие ) и dst - это статический массив (т.е. тип int[123]).

Если dst имеет неизвестный размер (т.е. int[]), то sizeof dst возвращает только размер указателя, так как dst был разложен на указатель. В этом случае вам нужно использовать sizeof(*dst)*ARRAY_LENGTH.

Ответ 5

Если вы выделили использование malloc, вы должны указать размер массива

int * src = malloc(ARRAY_LENGTH*sizeof(*src));
int * dst1 = malloc(ARRAY_LENGTH*sizeof(*dst));
memcpy(dst1,src,ARRAY_LENGTH*sizeof(*dst));

Если вы выделили статический массив, вы можете просто использовать sizeof

int dst2[ARRAY_LENGTH];
memcpy(dst2,src,sizeof(dst2));

Ответ 6

Предполагая, что dst имеет тип int *, sizeof (dst) вернет размер самого указателя (т.е. 4 в 32-битной системе, 8 в 64-битной системе), поэтому ваш второй пример будет только для каждой копии этого множества байты, в то время как первый будет правильно использовать фактический размер содержимого.

Ответ 7

Будет ли работать второй вариант? Независимо от содержания?

Он будет работать только при выполнении обоих условий:

  • dst - это обычный массив, а не указатель
  • src и dst имеют одинаковый размер

Ответ 8

sizeof (X) всегда дает вам количество байт "X" если X является массивом uint16_t из 10, тогда sizeof (X) вернет 20

uint16_t X[10]={0};
cout<<"sizeof x: "<<sizeof(X);

$> sizeof x: 20

если вы хотите количество элементов, которые вы должны выполнить бит байтовой арифметики:
8bit = 1byte
16bit = 2bytes
32bit = 4 байт
64bit = 8 байт

поэтому, чтобы получить количество элементов, которые вы могли бы сделать:

 numb_of_elements = ( sizeof(X)/sizeof(X[0]) );

в результате:

uint32_t source[100]={0};
memcpy((void*) dest, (void*) source, ( sizeof(source)/sizeof(source[0]) ));

конечно, вы, вероятно, захотите сделать (sizeof (X)/sizeof (X [0])) константу/переменную, чтобы вы не вычисляли каждый раз.. (я не знаю, будут ли компиляторы всегда оптимизируйте это)

Ответ 9

Это зависит. Оба arr и указатель представляют собой массивы, но sizeof() возвращает только правильный размер для arr, который объявляется во время компиляции.

int main() {
        int arr[10];
        int * pointer;
        pointer = (int *) malloc(10 * sizeof(int));
        printf("%d\n", sizeof(arr)); // 40
        printf("%d\n", sizeof(pointer)); // 4 or 8
        free(pointer);
}

Ответ 10

Если dst было выделено из кучи (например, с помощью malloc), второе решение не будет работать. sizeof (dst) будет работать только тогда, когда он будет известен компилятору. Например, следующий пример завершится неудачно, так как sizeof (dst) будет равен размеру указателя (4-8 байт.)

#define ARRAY_LENGTH 10
int *dst;

dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, sizeof(dst)); // sizeof dst in this case would be 4 bytes on 32 bit system

Этот сегмент кода будет работать каждый раз:

#define ARRAY_LENGTH 10
int *dst;

dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, ARRAY_LENGTH*sizeof(int)); // sizeof would be 40 bytes

Ответ 11

Как насчет?

memcpy(dst, src, &src[ARRAY_LENGTH] - &src[0]);

Это должно работать, даже если размер отдельных элементов меньше размера, выбранного каждым элементом в фактическом массиве.

Ответ 12

memcpy(), каково должно быть значение параметра размера?

Он должен быть минимальным между размером исходного буфера и размером целевого буфера.

Традиционно используется размер исходного буфера. Это иногда переполняло буфер назначения... Поэтому лучше использовать "безопасную" версию функции: одну, которая задает как размер источника, так и назначения.

У вас есть "более безопасные" функции, доступные через ISO/IEC TR24731. Там гораздо больше, например, согласованные возвращаемые значения и согласованное поведение обработки строк.

"Более безопасные" функции теперь являются частью стандарта C, поэтому он должен быть доступен везде. Поэтому вы должны использовать memcpy_s.

Вы не можете использовать его в Linux, потому что он не предоставляет функции (не верьте маркетинговой рекламе о стандартах)). В Linux вы должны "сворачивать свою собственную" оболочку.

Не все являются поклонниками более безопасных функций. См., Например, Используете ли вы TR безопасные функции? Об этом я могу сказать: Несколько переполнений буфера libunp. Миллионы маршрутизаторов и шлюзов подвержены множественным уязвимым местам, и многие из них остаются неповрежденными. И они были из-за ошибок, которые были бы остановлены более безопасными функциями. +1 всем, кто говорит: "Не используйте эту дерьмо Microsoft" .