我正在开发一个程序,我必须修改目标进程内存/读取它。
到目前为止,我使用void *来存储地址并将其转换为char *,如果我需要更改它们(添加偏移或修改一般)
我听说过在stdint.h中定义的那种类型,但是我没有看到使用它进行char *转换的指针算术的差异(这对我来说似乎更加C89友好)
所以我的问题:我应该将哪两种方法用于指针算法?我是否应该考虑在任何情况下使用uintptr_t而不是char *?
编辑1
基本上我只需要知道这是否会产生
while (( $# )); do
case "$1" in
--old-value) old+=("$2") ;;
--new-value) new+=("$2") ;;
--exclude) shift; exc=("$@") ; break ;;
--*) echo "bad arg" ; exit 1 ;;
esac
shift;shift
done
printf "old: %s\n" "${old[@]}"
printf "new: %s\n" "${new[@]}"
printf "exc: %s\n" "${exc[@]}"
答案 0 :(得分:6)
在评论中,用户 R .. 指出,如果代码处理的地址在当前进程中无效,则以下内容可能不正确。我已经要求OP澄清了。
如果您关心代码的可移植性,请不要将uintptr_t
用于指针运算。 uintptr_t
是整数类型。对它的任何算术运算都是整数运算,而不是指针运算。
如果您有一个void*
值并且想要为其添加字节偏移量,那么转换为char*
是正确的方法。
uintptr_t
值的算术可能与char*
算术的算法相同,但绝对不能保证。 C标准提供的唯一保证是您可以将void*
值转换为uintptr_t
并再次返回,结果将与原始指针值进行比较。
标准并不保证uintptr_t
存在。如果没有足够宽的整数类型来保存转换后的指针值而不丢失信息,那么实现就不会定义uintptr_t
。
我实际上在系统(Cray矢量机器)上工作,uintptr_t
上的算术不一定有效。硬件具有64位字,机器地址包含字的地址。类Unix操作系统需要支持8位字节,因此字节指针(void*
,char*
)包含一个字地址,其中3位偏移存储在其他未使用的高位3位中。 64位字。指针/整数转换只是复制了表示。结果是向char*
指针添加1将导致它指向下一个字节(在软件中处理偏移量),但转换为uintptr_t
并添加1会导致它指向下一个字。
底线:如果需要指针算法,请使用指针算法。这就是它的用途。
(顺便说一句,gcc有一个允许在void*
上进行指针运算的扩展。不要在便携式代码中使用它。它还会导致一些奇怪的副作用,比如sizeof (void) == 1
。)