如何解决为什么减去的内存地址数比预期的小?
typedef struct list {
struct list* next;
struct list* prev;
}list_t;
typedef struct node {
int value;
int key;
list_t list;
}node_t;
int main(void)
{
node_t alpha;
alpha.key = 10;
alpha.value = 11;
printf("&alpha.list address : %p - &alpha.key address : %p = %p",&alpha.list,&alpha.key,&alpha.list - &alpha.key);
return 0;
}
输出:
&alpha.list address : 0096F994 - &alpha.key address : 0096F990 = 00000000
为什么减去的内存地址数比预期的小? 我如何获得精确的减数?
解决方法
代码正在减去不同的指针类型。这给了我一个编译器错误。对于OP,谁知道不兼容的编译器可能会做什么?
error: invalid operands to binary - (have 'list_t *' {aka 'struct list *'} and 'int *')
由于指针的类型不同,建议先转换为通用的char*
。回想一下指针减法,区别在于引用类型的单位,在以下情况下为char
。
printf("%td\n",(char *)&alpha.list - (char *)&alpha.key);
当减去两个指针时,“ ....结果的大小是实现定义的,其类型(有符号整数类型)是ptrdiff_t
。” C17dr§6.5.6 9
使用"%td"
打印该差异。
如果您的编译器较旧且缺少"%td"
,请强制转换为广泛的可用类型。
// Alternative for old compilers. (pre-C99)
printf("%ld\n",(long) ((char *)&alpha.list - (char *)&alpha.key));
更深
减去不属于同一数组(或过去1个)的指针,即使它们都是同一结构的地址,也是麻烦的代码。
考虑使用offsetof(type,member-designator)
(返回size_t
)来查找偏移量。
printf("%zu\n",offsetof(node_t,list));
printf("%zu\n",key));
// 8
// 4
,
我认为您遇到麻烦的是您的类型。 %p用于打印指针,但指针减法的结果为int。另外,我相信对不同的指针类型(例如struct list *
和int *
)进行减法运算可能是不确定的……这意味着绝对可能发生任何事情。 gcc
会引发错误。
如果我这样做,将会得到正确的结果
printf("%p - %p = %ld\n",&alpha.list,&alpha.key,(void*)&alpha.list - (void*)&alpha.key);
编辑,以评论其中之一
根据规范的5.7节,未定义“不兼容的指针类型”的减法,因此任何结果都是可能的,并且绝对不应以任何可预测的方式指望它的行为。对于指针减法的结果,结果为ptrdiff_t
。根据第17.2.4节第2段:“类型ptrdiff_t是实现定义的带符号整数类型,可以在数组对象中保存两个下标的差...”是,void*
是未定义的( C规范的更新版本,顺便说一句,所以我在那里学到了一些东西。请改用其他任何字节大小的指针。
该限制表明必须对同一数组中的指针进行ptr减法,以防止发生不可预测的行为,该行为会导致对来自不同页面分配的地址进行数学运算。如果两个(不同类型的)地址来自同一分配,则数学将按预期工作。
使用gcc 9.3.0编译问题中存在的代码会给出:
error: invalid operands to binary - (have 'list_t *' {aka 'struct list*'} and 'int *')
切换到void *(或任何其他字节大小的指针)强制转换以避免编译器对指针类型的抱怨,会发出警告,强调强调的指针减法的完整性:
format '%p' expects argument of type 'void *',but argument has type 'long int'
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。