d的指针算术
原文
如下在ldc的更好C下编译:
import core.stdc.stdio;
import core.stdc.stdlib;
struct MemoryBlock {
char* ptr;
ulong length;
}
void* ptr = cast(void*)0x7a7;
void* right() {
return cast(MemoryBlock*)(ptr + MemoryBlock.sizeof);
//在括号间转换整个`式`.取正确的值!
}
//以上代码向`ptr`加了`16`个字节
void* wrong() {
return cast(MemoryBlock*)ptr + MemoryBlock.sizeof;
//先转换`'ptr'`变量,然后加上数字.得到错误的值...
}
//上面的代码向`ptr`加了`16*MemoryBlock.sizeof`字节`(16*16)`,因为先转换`ptr`,`+1`才是正确的
char* return_address_wrong() {
MemoryBlock* local_ptr = cast(MemoryBlock*)ptr;
return cast(char*)(local_ptr + MemoryBlock.sizeof);
//转换了整个式.但得到了错误的值`!!!!`为什么`???`
}
//因为加的是`16`字节块的指针,而不是单字节的`void*`
char* return_address_right() {
MemoryBlock* local_ptr = cast(MemoryBlock*)ptr;
return cast(char*)local_ptr + MemoryBlock.sizeof;
//现在我先转换`'local_ptr'`变量,然后加上数字,但这次得到了正确的值`..`,
}
//这是单个字节.
extern (C) void main() {
printf("期望位置:", ptr + MemoryBlock.sizeof);
printf("正确位置: %p\n", right());
printf("错误位置: %p\n", wrong());
printf("返回地址(错误)): %p\n", return_address_wrong());
printf("返回地址(正确): %p\n", return_address_right());
}
T*+10==10 * T.sizeof
在64位系统上,MemoryBlock.sizeof是16.
参考:
结果值是指针加上(或减去)第二个操作数乘以第一个操作数指向类型的大小.
因为加的是16字节块指针,而不是单字节的void*.
C和D根据基础值类型实现指针算术.即,向char*,加1加为基础地址加1,但向int*加1,则是基础地址加int.sizeof而不是1.即:
int[2] x;
int* p = &x[0]; // 假设这是1234地址
p++;//p现在为1238,而*不是*1235(int.sizeof==4)
因为更容易操作.
如,如果是指向4个有符号32位整数的数组,那么可简单地给指针递增1.
如果是原始字节,那么必须给指针加4才能移动到下个元素.
如果要移动到循环中的下个元素,这是反直觉的.
这是惯用法:
foreach (i; 0 .. list.length)
{
(*cast(int*)(ptr + i)) = i;
}
比较:
foreach (i; 0 .. list.length)
{
(*cast(int*)(ptr + (i * 4))) = i;
}
可这样:
foreach (i; 0 .. list.length) {
(cast(int*)ptr[i]) = i;
}
只要稍微移动右括号.可用指针加括号标记法.
假设ptr为void*,这些都是等价的:
(cast(int*) ptr)[i] = whatever;
*((cast(int*) ptr) + i) = whatever;
*(cast(int*) (ptr + i * int.sizeof)) = whatever;
浙公网安备 33010602011771号