2

I got structure:

typedef struct
{
    int a;
    int b;
    int c;
}Z;

code:

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);
}

output:

12
0x89a080 0x89a010
12297829382473034420

Why value in last line is so huge? Real address difference is 0x70 (16 bytes of heap allocation header plus 12*8 bytes of elements of array a), so from pointer's arithmetic I would expect value 0x70/12=9.(3) or 9 casted to integer. I know that substracted pointers don't point on the same arrays but I expected more reasonable result which would give me clue how memory map looks like. It was compiled on 64b Ubuntu and gcc 4.8.2.

assembly:

    .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
adashie
  • 616
  • 1
  • 5
  • 15

2 Answers2

6

Doing pointer arithmetic using unrelated pointers (like your a and b pointers) is undefined behavior.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 4
    +1, though it would be nice to have an understanding of why the implementation *would* report that `b - a` is `0x11111112`. (It *can* do *anything*. But we can still wonder about why it *does* do what it does.) – ruakh Feb 21 '15 at 18:07
6

From the draft 1570, this is

§6.5.6 Additive operators

  1. 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.

You cannot assume that the pointers will be contiguous, but in case they were the actual problem is the way arithmetic is peformed on the pointers because the poitners have type Z, and (void *)b - (void *a) != b - a.

So check this example to illustrate what I mean

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));

remember to include stddef.h for the ptrdiff_t type.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97