我正在测试一些计算函数大小的方法,以字节为单位(我熟悉 x86 上的操作码)。代码是不言自明的:
void exec(void* addr){
int (WINAPI *msg)(HWND,LPCSTR,LPCSTR,UINT)=(int(WINAPI *)(HWND,LPCSTR,LPCSTR,UINT))addr;
msg(0,"content","title",0);
}
void dump(){};
int main()
{
cout<<(char*)dump-(char*)exec; // this is 53
return 0;
}
它应该从'dump'中减去'exec'的地址。这可行,但我注意到使用其他类型的指针(如 DWORD*)时值不同:
void exec(void* addr){
int (WINAPI *msg)(HWND,LPCSTR,LPCSTR,UINT)=(int(WINAPI *)(HWND,LPCSTR,LPCSTR,UINT))addr;
msg(0,"content","title",0);
}
void dump(){};
int main()
{
cout<<(DWORD*)dump-(DWORD*)exec; // this is 13
return 0;
}
根据我的理解,无论指针类型如何,它始终是最大可能的数据类型(以便它可以处理大地址),在我的例子中是 4 字节(x86 系统)。指针之间唯一变化的是它指向的数据类型。
这是什么解释?
最佳答案
C/C++ 中的指针算法是为访问数组元素而设计的。事实上,数组索引只是指针运算的一种更简单的语法。例如,如果您有一个名为 array
的数组,则 array[1]
与 *(array+1)
相同,无论array
中元素的数据类型。
(我在这里假设没有运算符重载正在进行;这可能会改变一切。)
如果您有一个 char*
或 unsigned char*
,指针指向一个字节,递增指针会使它前进到下一个字节。
在 Windows 中,DWORD
是一个 32 位值(四个字节),DWORD*
指向一个 32 位值。如果您递增 DWORD*
,指针将前进 四个字节,就像 array[1]
为您提供数组的第二个元素一样,这是第一个元素之后的四个字节(一个 DWORD
)。同样,如果您将 10 添加到 DWORD*
,它会前进 40 个字节,而不是 10 个字节。
无论哪种方式,仅当结果指针指向与原始指针相同的数组或指向末尾后的一个元素时,递增或添加到指针才有效。否则就是未定义的行为。
指针减法和加法一样。当您从一个指针中减去另一个指针时,它们必须是同一类型,并且必须是指向同一数组的指针或指向末尾的指针。
您正在做的是计算两个指针之间的元素数量,就好像它们是指向同一个数组(或最后一个数组)的指针一样。但是当两个指针不指向同一个数组时(或者,一个指向末尾),结果是未定义的行为。
这是卡内基梅隆大学关于此的引用资料:
关于c++ - 简单的功能大小;了解指针与指针的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48310589/