复制包含长整数的字符串
Copying strings containing longs
我能够 "pack" 长字符串数组。现在,如果我 memcpy 包含 long 数组的字符串,内容就会丢失。这里有我的代码:
#include <stdio.h>
#include <string.h>
int main()
{
unsigned char arr[40];
unsigned char arr2[40];
unsigned int i = 0 ;
long f=0;
for ( i = 0 ; i < 5 ; i++ ) {
f = i + 1 ;
*((long *)arr + i*sizeof(long)) = f ;
}
memcpy(arr2, arr, 40);
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr2 + i*sizeof(long)) ;
printf("f =%ld from arr2 sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr + i*sizeof(long)) ;
printf("f =%ld from arr sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
}
这是输出:
f =1 from arr2 sizeof 0
f =0 from arr2 sizeof 8
f =1 from arr2 sizeof 16
f =140734674541394 from arr2 sizeof 24
f =140734674541702 from arr2 sizeof 32
f =1 from arr sizeof 0
f =2 from arr sizeof 8
f =3 from arr sizeof 16
f =4 from arr sizeof 24
f =5 from arr sizeof 32
如您所见,我可以读取存储在 "arr" 中但不能来自 "arr2" 的长值。有什么线索吗?
问题是你将(腐烂的)指针 arr
和 arr2
转换为 long*
,然后你不再有一个数组 ob 字节,而是一个 long
所以你的指针运算将不再正确(它假定指针是 char
的指针)。放弃乘法,只做例如
*((long *)arr + i) = f ;
(long *)arr2 + i*sizeof(long)
将由于越界缓冲区访问而导致未定义的行为。 (long *)arr2 + i
已经在 sizeof(long)
中编制索引。
所以你写的方式超过了 arr
的末尾,但只复制了它的前 40 个字节。除此之外,没有必要对未定义的行为进行推理。如果你幸运的话,它就会崩溃,从而立即表明你做错了什么。
将1
添加到指针p
和sizeof(*p) == 8
时,相当于将8
添加到char
指针。
换句话说,一旦你转换了指针,就没有必要再缩放索引了。
#include <stdio.h>
#include <string.h>
int main()
{
unsigned char arr[40];
unsigned char arr2[40];
unsigned int i = 0 ;
long f=0;
for ( i = 0 ; i < 5 ; i++ ) {
f = i + 1 ;
*((long *)arr + i) = f ;
}
memcpy(arr2, arr, 40);
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr2 + i) ;
printf("f =%ld from arr2 sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr + i) ;
printf("f =%ld from arr sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
}
虽然从技术上讲,您的程序仍然是未定义,因为它违反了严格别名。您可以通过使用 long 数组并通过 char 指针访问它,使用动态内存而不是 stack-allocated 数组,或者通过在循环的每次迭代中将 char 字节 memcpying 为临时 long 来解决这个问题(gcc 可以接受提示,最后一个解决方案最终并没有变得效率低下,尽管看起来是一个看似昂贵的函数调用。
你的问题出在几个表达式上
*((long *)arr + i*sizeof(long))
您需要决定是对 char
指针还是 long
指针进行指针运算。
如果你想在 char
指针上做,你从 arr
开始,添加 i*sizeof(long),然后转换为 long
指针:
arr
arr + i*sizeof(long)
(long *)(arr + i*sizeof(long))
另一方面,您也可以先将arr
转换为long
指针。但是,您不必乘以 sizeof(long)
,因为 long
指针的算术以 sizeof(long)
为单位,而不是字节:
arr
(long *)arr
((long *)arr + i)
我能够 "pack" 长字符串数组。现在,如果我 memcpy 包含 long 数组的字符串,内容就会丢失。这里有我的代码:
#include <stdio.h>
#include <string.h>
int main()
{
unsigned char arr[40];
unsigned char arr2[40];
unsigned int i = 0 ;
long f=0;
for ( i = 0 ; i < 5 ; i++ ) {
f = i + 1 ;
*((long *)arr + i*sizeof(long)) = f ;
}
memcpy(arr2, arr, 40);
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr2 + i*sizeof(long)) ;
printf("f =%ld from arr2 sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr + i*sizeof(long)) ;
printf("f =%ld from arr sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
}
这是输出:
f =1 from arr2 sizeof 0
f =0 from arr2 sizeof 8
f =1 from arr2 sizeof 16
f =140734674541394 from arr2 sizeof 24
f =140734674541702 from arr2 sizeof 32
f =1 from arr sizeof 0
f =2 from arr sizeof 8
f =3 from arr sizeof 16
f =4 from arr sizeof 24
f =5 from arr sizeof 32
如您所见,我可以读取存储在 "arr" 中但不能来自 "arr2" 的长值。有什么线索吗?
问题是你将(腐烂的)指针 arr
和 arr2
转换为 long*
,然后你不再有一个数组 ob 字节,而是一个 long
所以你的指针运算将不再正确(它假定指针是 char
的指针)。放弃乘法,只做例如
*((long *)arr + i) = f ;
(long *)arr2 + i*sizeof(long)
将由于越界缓冲区访问而导致未定义的行为。 (long *)arr2 + i
已经在 sizeof(long)
中编制索引。
所以你写的方式超过了 arr
的末尾,但只复制了它的前 40 个字节。除此之外,没有必要对未定义的行为进行推理。如果你幸运的话,它就会崩溃,从而立即表明你做错了什么。
将1
添加到指针p
和sizeof(*p) == 8
时,相当于将8
添加到char
指针。
换句话说,一旦你转换了指针,就没有必要再缩放索引了。
#include <stdio.h>
#include <string.h>
int main()
{
unsigned char arr[40];
unsigned char arr2[40];
unsigned int i = 0 ;
long f=0;
for ( i = 0 ; i < 5 ; i++ ) {
f = i + 1 ;
*((long *)arr + i) = f ;
}
memcpy(arr2, arr, 40);
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr2 + i) ;
printf("f =%ld from arr2 sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
for ( i = 0 ; i < 5 ; i++ ) {
f = *((long *)arr + i) ;
printf("f =%ld from arr sizeof %zu\n", f, (size_t)(i*sizeof(long)));
}
}
虽然从技术上讲,您的程序仍然是未定义,因为它违反了严格别名。您可以通过使用 long 数组并通过 char 指针访问它,使用动态内存而不是 stack-allocated 数组,或者通过在循环的每次迭代中将 char 字节 memcpying 为临时 long 来解决这个问题(gcc 可以接受提示,最后一个解决方案最终并没有变得效率低下,尽管看起来是一个看似昂贵的函数调用。
你的问题出在几个表达式上
*((long *)arr + i*sizeof(long))
您需要决定是对 char
指针还是 long
指针进行指针运算。
如果你想在 char
指针上做,你从 arr
开始,添加 i*sizeof(long),然后转换为 long
指针:
arr
arr + i*sizeof(long)
(long *)(arr + i*sizeof(long))
另一方面,您也可以先将arr
转换为long
指针。但是,您不必乘以 sizeof(long)
,因为 long
指针的算术以 sizeof(long)
为单位,而不是字节:
arr
(long *)arr
((long *)arr + i)