指针减法给出了奇怪的结果

时间:2015-02-21 17:53:07

标签: c gcc

我得到了结构:

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个字节的堆分配头加上数组a的12 * 8个字节的元素),所以从指针的算术我期望值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    $16, %rsp
    movl    $96, %edi
    call    malloc
    movq    %rax, -16(%rbp)
    movl    $96, %edi
    call    malloc
    movq    %rax, -8(%rbp)
    movl    $12, %esi
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf
    movq    -16(%rbp), %rdx
    movq    -8(%rbp), %rax
    movq    %rax, %rsi
    movl    $.LC1, %edi
    movl    $0, %eax
    call    printf
    movq    -8(%rbp), %rdx
    movq    -16(%rbp), %rax
    subq    %rax, %rdx
    movq    %rdx, %rax
    sarq    $2, %rax
    movq    %rax, %rdx
    movabsq $-6148914691236517205, %rax
    imulq   %rdx, %rax
    movq    %rax, %rsi
    movl    $.LC0, %edi
    movl    $0, %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

2 个答案:

答案 0 :(得分:5)

使用不相关的指针(如ab指针)进行指针运算是undefined behavior

答案 1 :(得分:5)

从草案1570开始,这是

  

§6.5.6加法运算符

     
      
  1. 当减去两个指针时,都指向同一个数组对象的元素,或者指向数组对象的最后一个元素;结果是两个数组元素的下标的差异。结果的大小是实现定义的,其类型(有符号整数类型)在ptrdiff_t标头中定义为<stddef.h>。如果结果在该类型的对象中无法表示,则行为未定义。换句话说,如果表达式PQ分别指向数组对象的第i个和第j个元素,则表达式(P)-(Q)具有值{{1如果值适合i−j类型的对象。此外,如果表达式P指向一个元素   一个数组对象或一个超过数组对象的最后一个元素,并且表达式ptrdiff_t指向   对于同一个数组对象的最后一个元素,表达式Q具有相同的元素   值为((Q)+1)-(P)((Q)-(P))+1,如果为,则值为零   表达式-((P)-((Q)+1))指向数组对象的最后一个元素,即使是   expression P不指向数组对象的元素。
  2.   

你不能假设指针是连续的,但是如果它们是实际的问题就是指针运算的方式,因为poitners有类型(Q)+1Z

请查看此示例以说明我的意思

(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)); 类型添加stddef.h