开发者

memcpy(), what should the value of the size parameter be?

开发者 https://www.devze.com 2022-12-27 10:14 出处:网络
I want to copy an int array to another int array. They use the same define for length so they\'ll always be of the same length.

I want to copy an int array to another int array. They use the same define for length so they'll always be of the same length.

What are the pros/cons of the 开发者_高级运维following two alternatives of the size parameter to memcpy()?

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

or

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

Will the second option always work? Regardless of the content?

One thing that favors the last one is that if the array were to change, it'll be some house-keeping to update the memcpy()'s.


As long as dst is declared as an array with a size, sizeof will return the size of that array in bytes:

int dst[ARRAY_LENGTH];

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

If dst just happens to be a pointer to the first element of such an array (which is the same type as the array itself), it wont work:

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

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


If you have allocated using malloc you must state the size of the array

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

If you have allocated with a static array you can just use sizeof

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


sizeof(dst) is correct only if dst is an array which size is known at compile time: like int arr[ARRAY_LENGTH] or a C99 variable length array; otherwise it returns the size of a pointer, not the length of the destination array.

To avoid future bug, be consistent and prefer the first form: size of type * length.


If and when you have an array (real one) you can use the sizeof(array) trick, but note that if you refactor the code and push it somewhere where the array has decayed into a pointer (or if the memory was initially allocated in a pointer (malloc/new) you will need to pass a known size.

Ignoring the relative sizes of source and destination, that is, assuming that they are the same for the rest of the discussion, if you are using C++ I would recommend a metaprogramming trick that will give you a typesafe size count for arrays and will fail to compile if you try to use it with pointers:

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

That way:

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
}

If at any time you refactor and the code moves to a place where the array has decayed (or you replace an static array for a dynamically allocated one) the compiler will tell you that you need to correct the size calculation.


Will the second option always work? Regardless of the content?

The 2nd option works only if you added back the missing ) and dst is a static array (i.e. of type int[123]).

If dst has unknown size (i.e. int[]), then sizeof dst only returns the pointer size, since dst has been decayed to a pointer. In this case, you need to use sizeof(*dst)*ARRAY_LENGTH.


Assuming dst is of type int*, sizeof(dst) will return the size of the pointer itself (i.e. 4 on a 32 bit system, 8 on a 64 bit system), so your second example will only every copy this many bytes, while the first one will correctly use the actual size of the content.


Will the second option always work? Regardless of the content?

It will work only if both conditions are satisfied:

  • dst is regular array, not pointer
  • src and dst are the same size


sizeof(X) always gives you the NUMBER OF BYTES of "X" if X is a uint16_t array of 10, then sizeof(X) will return 20

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

$> sizeof x: 20

if you want the number of elements you have to do a bit of byte arithmetic:
8bit = 1byte
16bit = 2bytes
32bit = 4 bytes
64bit = 8 bytes

so to get the number of elements you could do:

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

resulting in:

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

of course you would probably want to make ( sizeof(X)/sizeof(X[0]) ) a constant/variable so that you don't compute each time.. ( I don't know if compilers will always optimize this)


memcpy(), what should the value of the size parameter be?

It should be the minimum between the size of the source buffer and the size of the destination buffer.

Traditionally, the size of the source buffer has been used. That overflowed the destination buffer on occasion... So its better to use a "safer" version of the function: one that specifies both the source and destination buffer sizes.

You have "safer" functions available via ISO/IEC TR24731. There's a lot more to it, like consistent return values and consistent string handling behavior.

The "safer" functions are part of the C standard now, so its supposed to be available everywhere. So you should use memcpy_s.

You can't use it on Linux, because it does not provide the functions (don't believe the marketing hype about standards compliant)). On Linux, you should "roll your own" wrapper.

Not everyone is a fan of the safer functions. See, for example, Do you use the TR 24731 'safe' functions?. About all I can say about that is: Multiple libunp buffer overflows. Millions of routers and gateways are subject to multiple vulnerable and many remain unpatched. And they were due to bugs that would have been stopped by the safer functions. +1 to everyone who is saying "don't use this Microsoft crap".


It depends. Both arr and pointer are arrays, but sizeof() returns only the correct size for arr, which is declared at compile time.

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);
}


If dst was allocated from the heap (using malloc for example) the second solution will not work. sizeof(dst) will only work when it is know to the compiler. For example, the following example will fail as sizeof(dst) will be equal to the sizeof a pointer (4-8 bytes.)

#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

This code segment will work every time:

#define ARRAY_LENGTH 10
int *dst;

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


How about?

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

This should work even if the size of individual elements was smaller than the size taken by each item in the actual array.

0

精彩评论

暂无评论...
验证码 换一张
取 消