指针减法给出奇怪的结果
Pointer subtraction gives weird result
我得到了结构:
typedef struct
{
int a;
int b;
int c;
}Z;
代码:
int main()
{
Z *a = (Z*)malloc(sizeof(Z)*8);
Z *b = (Z*)malloc(sizeof(Z)*8);
printf("%lu\n", sizeof(Z));
printf("%p %p\n", b, a);
printf("%lu\n", b - a);
}
输出:
12
0x89a080 0x89a010
12297829382473034420
为什么最后一行的值这么大?实际地址差异是 0x70(16 字节的堆分配头加上 12*8 字节的数组 a 元素),因此根据指针的算术,我期望值 0x70/12=9.(3) 或 9 转换为整数。我知道减去的指针不指向相同的数组,但我希望得到更合理的结果,这会让我知道内存映射的样子。
它是在 64b Ubuntu 和 gcc 4.8.2.
上编译的
程序集:
.file "aa.c"
.section .rodata
.LC0:
.string "%lu\n"
.LC1:
.string "%p %p\n"
.text
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq , %rsp
movl , %edi
call malloc
movq %rax, -16(%rbp)
movl , %edi
call malloc
movq %rax, -8(%rbp)
movl , %esi
movl $.LC0, %edi
movl [=13=], %eax
call printf
movq -16(%rbp), %rdx
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl [=13=], %eax
call printf
movq -8(%rbp), %rdx
movq -16(%rbp), %rax
subq %rax, %rdx
movq %rdx, %rax
sarq , %rax
movq %rax, %rdx
movabsq $-6148914691236517205, %rax
imulq %rdx, %rax
movq %rax, %rsi
movl $.LC0, %edi
movl [=13=], %eax
call printf
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
使用不相关的指针(例如您的 a
和 b
指针)进行指针运算是 undefined behavior。
从草稿 1570 中,这是
§6.5.6 Additive operators
- When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is
ptrdiff_t
defined in the <stddef.h>
header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P
and Q
point to, espectively, the i-th and j-th elements of an array object, the expression (P)-(Q)
has the value i−j
provided the value fits in an object of type ptrdiff_t
. Moreover, if the expression P points either to an element of
an array object or one past the last element of an array object, and the expression Q
points
to the last element of the same array object, the expression ((Q)+1)-(P)
has the same
value as ((Q)-(P))+1
and as -((P)-((Q)+1))
, and has the value zero if the
expression P
points one past the last element of the array object, even though the
expression (Q)+1
does not point to an element of the array object.
您不能假定指针是连续的,但如果它们是连续的,那么实际问题是对指针执行算术的方式,因为指针的类型为 Z
和 (void *)b - (void *a) != b - a
。
所以检查这个例子来说明我的意思
Z *a;
Z *b;
Z *a = malloc(sizeof(Z) * 16);
if (a == NULL)
return -1;
b = a + 8;
printf("%lu\n", sizeof(Z));
printf("%p, %p\n", b, a);
printf("%lu\n", (ptrdiff_t)(b - a)); /* this will give wrong result */
printf("%lu\n", (ptrdiff_t)((void *)b - (void *)a));
记得为 ptrdiff_t
类型添加 stddef.h
。
我得到了结构:
typedef struct
{
int a;
int b;
int c;
}Z;
代码:
int main()
{
Z *a = (Z*)malloc(sizeof(Z)*8);
Z *b = (Z*)malloc(sizeof(Z)*8);
printf("%lu\n", sizeof(Z));
printf("%p %p\n", b, a);
printf("%lu\n", b - a);
}
输出:
12
0x89a080 0x89a010
12297829382473034420
为什么最后一行的值这么大?实际地址差异是 0x70(16 字节的堆分配头加上 12*8 字节的数组 a 元素),因此根据指针的算术,我期望值 0x70/12=9.(3) 或 9 转换为整数。我知道减去的指针不指向相同的数组,但我希望得到更合理的结果,这会让我知道内存映射的样子。 它是在 64b Ubuntu 和 gcc 4.8.2.
上编译的程序集:
.file "aa.c"
.section .rodata
.LC0:
.string "%lu\n"
.LC1:
.string "%p %p\n"
.text
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq , %rsp
movl , %edi
call malloc
movq %rax, -16(%rbp)
movl , %edi
call malloc
movq %rax, -8(%rbp)
movl , %esi
movl $.LC0, %edi
movl [=13=], %eax
call printf
movq -16(%rbp), %rdx
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl [=13=], %eax
call printf
movq -8(%rbp), %rdx
movq -16(%rbp), %rax
subq %rax, %rdx
movq %rdx, %rax
sarq , %rax
movq %rax, %rdx
movabsq $-6148914691236517205, %rax
imulq %rdx, %rax
movq %rax, %rsi
movl $.LC0, %edi
movl [=13=], %eax
call printf
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
使用不相关的指针(例如您的 a
和 b
指针)进行指针运算是 undefined behavior。
从草稿 1570 中,这是
§6.5.6 Additive operators
- When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is
ptrdiff_t
defined in the<stddef.h>
header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressionsP
andQ
point to, espectively, the i-th and j-th elements of an array object, the expression(P)-(Q)
has the valuei−j
provided the value fits in an object of typeptrdiff_t
. Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expressionQ
points to the last element of the same array object, the expression((Q)+1)-(P)
has the same value as((Q)-(P))+1
and as-((P)-((Q)+1))
, and has the value zero if the expressionP
points one past the last element of the array object, even though the expression(Q)+1
does not point to an element of the array object.
您不能假定指针是连续的,但如果它们是连续的,那么实际问题是对指针执行算术的方式,因为指针的类型为 Z
和 (void *)b - (void *a) != b - a
。
所以检查这个例子来说明我的意思
Z *a;
Z *b;
Z *a = malloc(sizeof(Z) * 16);
if (a == NULL)
return -1;
b = a + 8;
printf("%lu\n", sizeof(Z));
printf("%p, %p\n", b, a);
printf("%lu\n", (ptrdiff_t)(b - a)); /* this will give wrong result */
printf("%lu\n", (ptrdiff_t)((void *)b - (void *)a));
记得为 ptrdiff_t
类型添加 stddef.h
。