*(long *) 和 *(int*) 是什么意思?
What does *(long *) and *(int*) mean?
你能解释一下接下来的两行是做什么的吗?
// Line 1
*(long *)add1= *(long *)add2;
// Line 2
*(int *)add1 = *(int *)add2;
编辑 1. 我添加了我测试的函数的完整代码块。
PS 这只是脚本的一部分。 [original Skript]
这是一个自定义的 memcpy 函数,用于将内存块从 A 复制到 B。
(2)
while(word_left > 0){
*(char *)temp++ = *(char *)src++;
word_left --;
}
return (void *)dest;
}
太客气了,解释了 part(1) 中的行是什么意思。
我的问题是关于第(2)部分的。如果内存地址重叠,这部分应该可以解决问题。
这里为什么要用char
?为什么我们不能使用 long
或 int
?
两个记录中的const6ructions ( long * )
和( int * )
表示将指针对应地转换为指针类型long *
和int *
。然后这些指针被取消引用 *( long * )addr2
和 *( int * )addr2
以访问指向的对象,这些对象的值被分配给其他对象,这些对象也通过强制转换和取消引用指针获得。
为了更清楚地考虑演示程序。
#include <stdio.h>
int main(void)
{
int x = 10;
int y = 0;
printf( "x = %d, y = %d\n", x, y );
void *p1 = &x;
void *p2 = &y;
*( int * )p2 = *( int * )p1;
printf( "x = %d, y = %d\n", x, y );
return 0;
}
程序输出为
x = 10, y = 0
x = 10, y = 10
例如,在这个程序中,由于强制转换 ( int * )p1
,void *
类型的指针 p1
被解释为指向 int *
类型的指针int
类型的对象(在本例中它指向对象 x
)。现在取消引用此指针 *( int * )p1
您可以直接访问指向的对象 x
.
你可能不只是写例子
y = *p1;
因为您不能取消引用 void 指针,因为类型 void
是不完整的类型。所以编译器将不知道如何解释指向的内存。
C 标准函数memcpy
有时以类似的方式实现。该函数不要求应用程序传递的地址对齐。
一个简单的版本可以 运行 使用 char
字节类型的 for 循环并逐字节复制所有内容。这样我们就不必担心对齐问题,但是这样的代码会很慢,因为它没有利用 CPU 数据宽度。
更高效的代码将在 CPU 可以在单个指令中处理的最大数据大小上进行复制,例如 32 或 64 位。这应该是这段代码应该做的。如果这样做,我们仍然需要注意要复制的段末尾的起始字节和尾随字节的潜在错位。该部分必须逐字节复制,类似于函数末尾的代码。
这是我们注意到您发布的代码严重损坏的第一个地方 - 它无法处理初始错位。
更糟糕的是,它假定 int cpu_size = sizeof(char *);
给出了 CPU 数据宽度大小,这显然是错误的——指针的大小对应于 地址总线宽度 这与许多现有系统上的最大数据寄存器宽度不同。
另一个 problem/bug 是 temp += cpu_size;
不是有效的 C 代码,而是一个非标准的 gcc 扩展。我们不能对 void 指针进行指针运算。
外观错误是 void*
和 void*
之间的演员表。显然我们不需要在相同类型之间进行转换。实际上,C 中的每个对象指针都可以隐式转换为 void*
,无需强制转换,前提是限定符(const
等)匹配。
最后,我们不能在标准 C 编译器上 运行 编写这样的代码,因为使用 long
或 int
的值访问取消引用某些未知数据很可能是未定义的行为和严格的别名违规。 What is the strict aliasing rule? 作为标准库一部分的实际 memcpy 函数不是用标准 C 编写的,因此无法编译。 (它很可能是用汇编程序编写的,并且经常内联在调用代码中。)
所以你应该对这段代码做的是删除它并忘记你曾经见过它,因为没有什么可以从中学习的。写它的人不知道他们在做什么。通过“尤达条件”混淆,它看起来像是 1980 年代的代码 - 如果是这样,那么我建议避免研究那样的非常古老的代码。
你能解释一下接下来的两行是做什么的吗?
// Line 1
*(long *)add1= *(long *)add2;
// Line 2
*(int *)add1 = *(int *)add2;
编辑 1. 我添加了我测试的函数的完整代码块。 PS 这只是脚本的一部分。 [original Skript]
这是一个自定义的 memcpy 函数,用于将内存块从 A 复制到 B。
(2)
while(word_left > 0){
*(char *)temp++ = *(char *)src++;
word_left --;
}
return (void *)dest;
}
我的问题是关于第(2)部分的。如果内存地址重叠,这部分应该可以解决问题。
这里为什么要用char
?为什么我们不能使用 long
或 int
?
两个记录中的const6ructions ( long * )
和( int * )
表示将指针对应地转换为指针类型long *
和int *
。然后这些指针被取消引用 *( long * )addr2
和 *( int * )addr2
以访问指向的对象,这些对象的值被分配给其他对象,这些对象也通过强制转换和取消引用指针获得。
为了更清楚地考虑演示程序。
#include <stdio.h>
int main(void)
{
int x = 10;
int y = 0;
printf( "x = %d, y = %d\n", x, y );
void *p1 = &x;
void *p2 = &y;
*( int * )p2 = *( int * )p1;
printf( "x = %d, y = %d\n", x, y );
return 0;
}
程序输出为
x = 10, y = 0
x = 10, y = 10
例如,在这个程序中,由于强制转换 ( int * )p1
,void *
类型的指针 p1
被解释为指向 int *
类型的指针int
类型的对象(在本例中它指向对象 x
)。现在取消引用此指针 *( int * )p1
您可以直接访问指向的对象 x
.
你可能不只是写例子
y = *p1;
因为您不能取消引用 void 指针,因为类型 void
是不完整的类型。所以编译器将不知道如何解释指向的内存。
C 标准函数memcpy
有时以类似的方式实现。该函数不要求应用程序传递的地址对齐。
一个简单的版本可以 运行 使用 char
字节类型的 for 循环并逐字节复制所有内容。这样我们就不必担心对齐问题,但是这样的代码会很慢,因为它没有利用 CPU 数据宽度。
更高效的代码将在 CPU 可以在单个指令中处理的最大数据大小上进行复制,例如 32 或 64 位。这应该是这段代码应该做的。如果这样做,我们仍然需要注意要复制的段末尾的起始字节和尾随字节的潜在错位。该部分必须逐字节复制,类似于函数末尾的代码。
这是我们注意到您发布的代码严重损坏的第一个地方 - 它无法处理初始错位。
更糟糕的是,它假定 int cpu_size = sizeof(char *);
给出了 CPU 数据宽度大小,这显然是错误的——指针的大小对应于 地址总线宽度 这与许多现有系统上的最大数据寄存器宽度不同。
另一个 problem/bug 是 temp += cpu_size;
不是有效的 C 代码,而是一个非标准的 gcc 扩展。我们不能对 void 指针进行指针运算。
外观错误是 void*
和 void*
之间的演员表。显然我们不需要在相同类型之间进行转换。实际上,C 中的每个对象指针都可以隐式转换为 void*
,无需强制转换,前提是限定符(const
等)匹配。
最后,我们不能在标准 C 编译器上 运行 编写这样的代码,因为使用 long
或 int
的值访问取消引用某些未知数据很可能是未定义的行为和严格的别名违规。 What is the strict aliasing rule? 作为标准库一部分的实际 memcpy 函数不是用标准 C 编写的,因此无法编译。 (它很可能是用汇编程序编写的,并且经常内联在调用代码中。)
所以你应该对这段代码做的是删除它并忘记你曾经见过它,因为没有什么可以从中学习的。写它的人不知道他们在做什么。通过“尤达条件”混淆,它看起来像是 1980 年代的代码 - 如果是这样,那么我建议避免研究那样的非常古老的代码。