原文
如下在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;