6

I'm trying to find the distance in memory between two variables. Specifically I need to find the distance between a char[] array and an int.

    char data[5];
    int a = 0;

    printf("%p\n%p\n", &data[5], &a);

    long int distance = &a - &data[5];

    printf("%ld\n", distance);

When I run my my program without the last two lines I get the proper memory address of the two variables, something like this:

   0x7fff5661aac7
   0x7fff5661aacc

Now I understand, if I'm not wrong, that there are 5 bytes of distance between the two (0x7fff5661aac8, 0x7fff5661aac9, 0x7fff5661aaca, 0x7fff5661aacb, 0x7fff5661aacc).

Why I can't subtract a pointer of type (int *) and one of type (char *). Both refer to memory address.. What should I do in order to calculate the distance, in bytes, between the two?? I tried casting one of the two pointers but it's not working.

I get: "error: 'char *' and 'int *' are not pointers to compatible types". Thanks to everyone will help me

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
fedemengo
  • 626
  • 2
  • 7
  • 24
  • 1
    "Both refer to memory address" - Not according to the standard. Could as well be hashes to a database. – too honest for this site Nov 16 '16 at 12:08
  • The reason you don't have the ability to compare or take differences between pointers do different types is because they might not even be on the same address space. For example in Harvard architecture pointer to function and pointer to data lie in different spaces and 1 can be valid address on both. Similarly in those architectures constants might be put in the same space as code and 2 distinct arrays of type `const int*` and `int*` might have exactly the same address. In DOS near pointers might be exactly the same but they might be pointed to different segments. – phuclv Nov 16 '16 at 12:59
  • 1
    @Olaf What makes you say that? n1570, 6.5.3.2/3: "The unary & operator yields the address of its operand." What type of memory is addressed is unspecified, true; it may be a database, or flash, or a toilet paper roll. But it is memory which is byte-wise addressable. The sentence "Both [valid pointers] refer to memory address[es]" is perfectly correct in any conceivable way. By the way, we can safely conclude from the numerical values of the addresses that any hashing algorithm would be deeply flawed; Occam's razor makes me biased towards a linear memory model. – Peter - Reinstate Monica Nov 16 '16 at 13:45
  • The question in the duplicate link is related but not the same: The other program involved two pointers of the same type, making the program compile and run. This one here violates a constraint though which is diagnosed by the compiler. – Peter - Reinstate Monica Nov 16 '16 at 17:40

7 Answers7

11

Nopes, this is not possible.

First, you can only subtract pointers of (to) "compatible" types, an int and a char are not compatible types here. Hence the subtraction is not possible.

That said, even if both are pointers to compatible type, then also, the following comes into picture.

So, secondly You cannot just subtract two arbitrary pointers, they need to be essentially part of (address for elements of) the same array. Othweise, it invokes undefined behavior.

Quoting C11, chapter §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. [....]

Thirdly, another important point, the result of subtraction of two pointers is of type ptrdiff_t, a signed integer type.

[...] The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. [...]

so, to print the result, you need to use %td format specifier.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • Make "array" "object": It is legal to compute offsets of struct members. – Peter - Reinstate Monica Nov 16 '16 at 11:51
  • 2
    @PeterA.Schneider: That's what `offsetof` is for. Can you provide a reference to where the standard allows this for pointers? IIRC, there is no such exception (and the implementtion of `offsetof` is implementation-specific. – too honest for this site Nov 16 '16 at 11:58
  • You are right, directly subtracting pointers to members is not allowed (and often wouldn't make sense, due to different types and padding). I wanted to express that they do have a guaranteed relation to each other in memory, as opposed to unrelated objects. But that doesn't make it valid to subtract unconverted pointers. – Peter - Reinstate Monica Nov 16 '16 at 12:06
  • @PeterA.Schneider: What do you mean with "guranteed relation"? It is UB, so what guarantee would be there? – too honest for this site Nov 16 '16 at 12:10
  • @Olaf I mean exactly that. As you correctly said, it's possible to establish a member's address offset to the struct's address, and hence their address, and that member is guaranteed to be there for every struct of that type (compiled with the same compiler and settings). This guarantee does not exist for unrelated objects. You can take the struct's address and cast it to an integer (if possible), add the offset, cast it to the member's type pointer and access it. Nothing about that is undefined. After converting to integers you can also subtract the two and always get the offset. – Peter - Reinstate Monica Nov 16 '16 at 12:19
  • "You can take the struct's address ..." - No that invokes undefined behaviour! Conversion to/from an integer is implementation defined, but once you do arithmetics on that value and cast that back to a pointer, you invoke UB. Also for a second reason: you may only convert a pointer types to an integer and back to **the same type**. – too honest for this site Nov 16 '16 at 12:27
  • @Olaf I'll answer to that in my own answer. – Peter - Reinstate Monica Nov 16 '16 at 12:30
  • 2
    A minor nitpick: I think the attempt to subtract two pointers of incompatible type is what the standard calls a *constraint violation* (the violated rule appears in the *Constraints* section of 6.5.6 in n1570). A *constraint* in standardese is a violation of the language rules which a conformant compiler must diagnose at compile time. That's why the OP cannot compile and run his program but correctly gets the reported errors. UB is not possible because no executable is produced. – Peter - Reinstate Monica Nov 16 '16 at 13:12
  • @PeterA.Schneider Whoa...that's not a nitpick, I kind of missed that point... Need to update, thanks for noticing.. – Sourav Ghosh Nov 16 '16 at 13:22
  • @PeterA.Schneider: Nitpick on the nitpick: It **would invoke UB**. With some more effort, one can produce code which lets the compiler not detect this situation, so he cannot show a diagnostic message (e.g. a cast). That would not change the UB, just silence the constraint disagnostic. Btw.: The standard only uses the term "diagnostic message", not "error" or "warning". It also does not disallow generating code for such violations. – too honest for this site Nov 16 '16 at 17:41
  • @Olaf How would you go about fooling the static type analysis for expressions? (Oh, I see what you mean -- with a cast. That changes the type of the expression though, and removes that particular constraint violation.) – Peter - Reinstate Monica Nov 16 '16 at 17:43
  • @PeterA.Schneider: It does not remove the UB, though. – too honest for this site Nov 16 '16 at 18:10
2

On a standard PC nothing keeps you from casting both pointers to an integer type which can hold the pointer value, and subtracting the two integers.

Such an integer type is not guaranteed to exist on all architectures (but on many common systems it does) — imagine segmented memory with more information than just a single number. If the integer type doesn't fit, the behavior of the cast is undefined.

From the standard draft n1570, 6.3.2.3/6:

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

Often the difference between addresses will be what one expects (variables declared in succession are next to each other in memory) and can be used to tell the direction the stack grows etc.


It may be interesting to explore what else you can do with integers and pointers.

Olaf commented that if you "cast [an arithmetic computation result] back to a pointer, you invoke UB." That is not necessarily so; it depends on the integer value. The standard draft says the following in 6.3.2.3/5:

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation

(Emphasis by me.) If we compute the address of a struct member by adding an offset to the struct's address we have obviously taken care of the mentioned issues, so it's up to the implementation. It is certainly not UB; a good many embedded systems would fail if we couldn't use an integer -> pointer conversion, and access that memory through the resulting pointer. We must make sure that the system allows it, and that the addresses are sound.

The paragraph has a footnote:

The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.

That is, they are meant to not surprise the user. While in theory the addresses of unrelated objects adjacent in memory could be projected to wildly different integer values, they are not supposed to. A user can for example reasonably expect that linear memory is projected into a linear integer number space, keeping ordering and distances.


I should also emphasize (as I did in one comment) that the standard is not the world. It must accommodate and give guarantees for a wide range of machines. Therefore the standard can only be the smallest common denominator. If we can narrow the range of architectures we consider, we can make much better guarantees.

One common example is the possible presence of trap values in integer registers, or flags indicating a read from an uninitialized register, which also traps; these are responsible for a wide range of UB cases in the standard which simply do not apply, for example, to your PC.

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • The standard does not define how the conversion is done, if it is in any way meaningful. Less does it define what the difference of such converted pointers is. So the result of this difference is completely useless. – too honest for this site Nov 16 '16 at 12:17
  • 2
    @Olaf Well, looking at the numerical values of addresses allows you, for example, to reverse-engineer a dynamic allocator; or inject code through a buffer overflow. I would not call that useless. *The standard is not the world; it is the smallest common denominator.* – Peter - Reinstate Monica Nov 16 '16 at 12:23
  • 1
    We don't have any details about the specific implementation, thus the standard is only what we have here. Said that, it is a question about standard behaviour! – too honest for this site Nov 16 '16 at 12:30
  • 1
    @Olaf I don't see the word "standard" in the question; the question appears wholly pragmatic: "Why I can't subtract a pointer of type (int *) and one of type (char *). Both refer to memory address.. What should I do in order to calculate the distance, in bytes, between the two?? " It is a perfectly reasonable question to ask, and it has a perfectly reasonable answer (which I gave here). – Peter - Reinstate Monica Nov 16 '16 at 12:48
  • @Olaf And Re "We don't have any details about the specific implementation": But we do -- the OP posted two addresses of local variables, 5 bytes apart, high in the address range. This points to a stack at the end of the address space growing up... – Peter - Reinstate Monica Nov 16 '16 at 12:58
  • I know quite some embedded systems which have Flash in that location. That's no proof at all. Less, as we don't even know which platform it is. Better don't make assumptions an stick to the information given. – too honest for this site Nov 16 '16 at 13:09
  • @Olaf I couldn't care less about the underlying hardware of that byte-addressable read-write memory. What I said about the stack is observation, not assumption. What you said was an assumption, not an observation, and right: We should not make those. – Peter - Reinstate Monica Nov 16 '16 at 13:54
  • @PeterA.Schneider you exactly understand what I meant with the question! Very interesting topic – fedemengo Nov 17 '16 at 15:58
2

Pointer subtraction is only defined for pointers within the same array (or just past the last element of an array). Any other use is undefined behavior. Let's ignore that for your experimentation.

When two pointers of the same type to elements of the same array object are subtracted, the result is the difference of the array indices. You could add that signed integer result (of type ptrdiff_t) to the first pointer and get the value of the second pointer, or subtract the result from the second pointer and get the value of the first pointer. So in effect, the result is the difference in the byte address of the two pointers divided by the size of the object being pointed to. This is why it makes no sense to allow subtraction of pointers of incompatible type, particularly when the referenced object types are of different size. How could you divide the difference in byte address by the size of the object being pointed to when the pointers being subtractedare referring to differently sized objects?

Still, for experimentation purposes, you can cast both pointers (pointing to different objects) to char * and subtract them, and many compilers will just give you the difference in their byte address as a number. However, the result could overflow an integer of ptrdiff_t. Alternatively, you can convert both pointers to an integer of type intptr_t and subtract the integers to get the difference in byte address. Again, it's theoretically possible that the result of the subtraction could overflow an integer of type intptr_t.

Ian Abbott
  • 15,083
  • 19
  • 33
  • _"How could you divide the difference in byte address by the size of the object being pointed to when the pointers being subtractedare referring to differently sized objects?"_ as you said is just for experimentation purpose. In this case, the unknown object type you're referring is the one stored between the two address I get (0x7fff5661aac8, 0x7fff5661aac9, 0x7fff5661aaca, 0x7fff5661aacb)? Or it would be the type (int *and char *) that in some cases might be unknown a priori? EDIT: or both? – fedemengo Nov 17 '16 at 16:06
  • In your case, for your experiment, you can just use `long int distance = (char *)&a - &data[5];` to subtract two `char *`s. A `char *` points to the smallest addressable object, which is a "byte" in C terminology, and is likely to be the same as a common parlance "byte" unless you have a somewhat exotic computing environment. – Ian Abbott Nov 17 '16 at 17:03
1
uint8_t * ptr = ...;
uint8_t * ptr2 = ptr + 5;

Now if ptr was 100, what will ptr2 be? Correct, it will be 105. But now look at that code:

uint32_t * ptr = ...;
uint32_t * ptr2 = ptr + 5;

Again, if ptr was 100, what will ptr2 be? Wrong! It won't be 105, it will be 120.

Why? Pointer arithmetic is not integer arithmetic!

ptr2 = ptr + 5;

Actually means:

ptr2 = int_to_ptr(ptr_to_int(ptr) + (sizeof(ptr) * 5));

Functions int_to_ptr and ptr_to_int don't really exist, I'm just using them for demonstration purpose, so you better understand what is going on between the scenes.

So if you subtract two pointers, the result is not the difference of their addresses, it's the number of elements between them:

uint32_t test[50];
ptrdiff_t diff = &test[20] - &test[10];

diff will be 10, as there are 10 elements in between them (one element is one uint32_t value) but that doesn't mean there are 10 bytes between test[10] and test[20], there are 40 bytes between them as every uint32_t value takes up 4 bytes of memory.

Now you may understand why subtracting pointers of different types makes no sense, as different types have different element sizes and what shall such a subtraction then return?

If you want how many bytes are in between two pointers, you need to cast them both to a data type that has one-byte elements (e.g. uint8_t * or char * would work) or cast them to void * (GNU extension but many compilers support that as well), which means the data type is unknown and thus the element size is unknown as well and in that case the compiler will byte-sized elements. So this may work:

ptrdiff_t diff = (void *)ptr2 - (void *)ptr1;

yet this

ptrdiff_t diff = (char *)ptr2 - (char *)ptr1;

is more portable.

It will compile, it will deliver an result. If that result is meaningful, that's a different topic. Unless both pointers point to the same memory "object" (same struct, same array, same allocated memory region), it is not, as the standard says that in that case, the result is undefined. That means diff could (legally) have any value, so a compiler may as well always set diff to 0 in that case, that would be allowed by the standards.

If you want defined behavior, try this instead:

ptrdiff_t diff = (ptrdiff_t)ptr2 - (ptrdiff_t)ptr1;

That is legal and defined. Every pointer can be casted to an int value and ptrdiff_t is an int value, one that is guaranteed to big enough so that every pointer can fit into it (don't ever use int or long for that purpose, they do not make any such guarantee!). This code converts both pointers to integers and then subtract them. I still don't see anything useful you can do with diff now, but that code at least will deliver a defined result, yet maybe not the result you might be expecting.

Mecki
  • 125,244
  • 33
  • 244
  • 253
  • 3
    Conversions from pointers to integer is implementation defined and may cause undefined behavior in case of trap representations (6.3.2.3 §5). Also types uintptr_t or intptr_t should be preferred for pointer storage as they are, unlike ptrdiff_t, explicitly defined for this purpose (7.20.1.4§1). – 2501 Nov 16 '16 at 12:12
  • 1
    "Now if ptr was 100, what will ptr2 be? Correct, it will be 105. But now look at that code:" - Wrong. It will invoke undefined behaviour, unless it points to (or exactly past) the same array. – too honest for this site Nov 16 '16 at 12:20
  • @2501 Secondly: Any pointer fits into `ptrdiff_t` by definition as I can always subtract `(ptrdiff_t)0` from another pointer, thus casting a pointer to `ptrdiff_t` is always save and can never fail. Also `ptrdiff_t` is older than `uintptr_t` and thus far wider supported. And that the result of this conversion is implementation defined it totally irrelevant here, as you cannot do anything meaningful with diff anyway. – Mecki Nov 16 '16 at 12:22
  • @Olaf No, it will not invoke undefined behavior, it **could** invoke undefined, but as you don't know what `ptr` is (who says it isn't a pointer to an array of 100 `uint32_t` values?) you cannot make claims like that. Please refrain from commenting on the basis of things you *do not know*, only make comments on the basis of things that *you do know*. And you just don't know what `ptr` is in my code, as `...` is a place holder. – Mecki Nov 16 '16 at 12:25
  • You should have read the whole comment of mine! Problem is you don't show exactly this relevant part in your answer, thus my comment is correct as it stands. I'm not a clairvoyant and most beginners aren't either. If you provide incomplete answers, comments pointing at the missing parts are to be expected. If you don't like them, be clear about what you mean! – too honest for this site Nov 16 '16 at 12:33
  • 2
    `(ptrdiff_t)0` when used in pointer context, is a _null pointer constant_. Difference between any valid pointer and a _null pointer_ is undefined behaviour. Thus you prove nothing. And no, `ptrdiff_t` is **not** guaranteed to hold a pointer. Feel free to provide a reference to where ste standard states different. As @2501 wrote, only `(u)intptr_t` are guaranteed to hold a pointer. But only for conversion from/to, not arithmetics. Don't confuse the abstract machine with a specific implementation. – too honest for this site Nov 16 '16 at 12:40
  • @Olaf `ptrdiff_t` is an int value. `ptridiff_t p = 0` is no different than `int i = 0`. `ptrdiff_t` has no special meaning, other than that the standard says that any possible pointer difference will fit into it. `ptrdiff_t` is not a NULL pointer, it is an integer of unknown size whose value is 0. And the standard doesn't have to define that `ptrdiff_t` can hold any pointer as that is logically derived by the guarantee that it can hold any pointer diff. – Mecki Nov 16 '16 at 12:46
  • 1
    Please note that I mostly agree with your answer and I have not downvoted it. But in favor of improving it, I have posted that first comment. SO is a collaboration, remember that. – 2501 Nov 16 '16 at 13:03
  • "any possible pointer difference will fit into it." - Which does not imply it will fitz a pointer itself! The allowed difference of pointer can be smaller than the size of a pointer. Just consider a 68000 system, where the max. size of an array could well fit into an `int16_t` (the 68000 was a 16 bit CPU with 32 bit registers and operations), but pointers were 32 bit (24 + 8 unused actually). And, again, `(ptrdiff_t)0` is **not the same** as `ptrdiff_t p`. You should be less careless when it comes to relevant details. – too honest for this site Nov 16 '16 at 13:03
  • `ptrdiff_t diff = (void *)ptr2 - (void *)ptr1;` is a compile time error: `error: pointer of type 'void *' used in subtraction [-Werror=pointer-arith]`. – mch Nov 16 '16 at 13:29
  • @mch If you tell your compiler to report that kind of pointer arithmetic as an error (that's what the option `-Werror=pointer-arith` does!), then of course it will be an error. But under normal circumstances it is not. See here, you can even run that code online and it runs just fine: http://rextester.com/MFVL71506 – Mecki Nov 16 '16 at 13:34
  • @Mecki look at the warning `warning: arithmetic on pointers to void is a GNU extension`. – mch Nov 16 '16 at 13:37
  • 1
    @mch Yes, you are correct, this is not standard, albeit widely supported by almost all compilers. If you tell your compiler to allow GNU extensions, you also don't get a warning ; of course the compiler will complain if you tell it t strictly enforce ISO-C. I point that out in my reply. – Mecki Nov 16 '16 at 13:44
  • @Olaf The maximum size of an array in C is only defined by the size of `size_t`. Something like segmented memory may limit the maximum linear mem block, but segments are alien to C and memory can very well cross segment borders. It's task of the compiler/OS to handle such situations. My C compiler for 68000 says `size_t` is 32 bit and `ptrdiff_t` is always the signed integer type that `size_t` is. Also note that `[u]intptr_t` are optional types (7.20.1.4), the compiler may not even know these, but `ptrdiff_t` is a mandatory type and the only type you can thus rely to be present. – Mecki Nov 16 '16 at 14:25
  • 1
    @2501 Also if you had read 7.20.1.4, you'd know that `[u]intptr` are optional type, you cannot rely that they even exist, a compiler is ISO C conform if it never heard of that type. `ptrdiff_t` is a mandatory type, every compiler aiming at standard compatibility must support it. So it's the only type guaranteed to be portable and should there ever be a platform where a pointer does not fit into `ptrdiff_t`, then hell would break lose. Most operating system can impossibly even run on such a platform. I prefer to show working code then nitpicking on standards, which really helps nobody on earth. – Mecki Nov 16 '16 at 14:28
  • To those complaining about this answer: It is the only answer I understand to be addressing the core request of the OP: "I'm trying to find the distance in memory between two variables." And does a remarkable job of explaining a lot about pointers and memory. – Confused Nov 16 '16 at 15:04
  • @Confused: Understandability does not allow incorrectness or carelessness. – too honest for this site Nov 16 '16 at 16:37
  • @Mecki: I cited values from an older compiler. `size_t` defines the max. **size** of an array in bytes. `ptrdiff_t` the max. difference of two pointer in terms of indexes. Said that, an architecture may allow `SIZE_MAX` to be 32767, i.e. what a 16 bit `ptrdiff_t` can represent, yet use 32 bit (or 20 bit) pointers. See 8086. There is no need to put something into my words. I did not mention segmentation at all and there is no need for that. `(u)intptr_t` are the **only** integers guaranteed to hold any pointer type (indirectly, as they strictly require first a conversion to `void *`). ... – too honest for this site Nov 16 '16 at 16:42
  • 1
    ... they are optional for the simple reason that there might be no conversion from pointer to integer, as that is implementation defined. Any modern compiler will provide them if the architecture allows for them. It is much like making the fixed-width types optional. Let that apart, you still don't provide a reference where the standard allows arithmetic on such a converted pointer and back. Even for standard integer types, there is only the conversion from/to of the same type allowed and nothing about changing the value. – too honest for this site Nov 16 '16 at 16:44
  • @Olaf You say `I cited values from an older compiler.` but then you argue on the latest C standard (how would that fit together) and one comment later you say `Any modern compiler ....` Okay, what are we talking about here? An abstract, theoretical standard? An old compiler nobody uses anymore? Or "any modern compiler"? You jump wherever it pleases you. Well, any modern compiler will have `ptrdiff_t` where any pointer fits as this type is widely used in million of C code lines and some of these even pre-dates the latest standard by several years. – Mecki Nov 16 '16 at 16:54
  • Nonsense, @Olaf. On all counts. If you're so wise on this, write a better answer. The principles, processes and practicalities of finding the distance between variable pointers is understandable in this answer, which makes it brilliant, and correct, regardless of whatever you're talking about, which is completely incomprehensible in the comments format. You're well past the point where writing your own answer would be a far better way to make your points. This cramped and unformatted space isn't helping you articulate whatever you're trying to say. – Confused Nov 16 '16 at 16:54
  • The original question is "how do I do that" and I'm pretty sure my answer is exactly the correct and working answer to that question. Everything else nitpicking about theoretical situations nobody cares for as they just don't relate to this concrete question at all. If the poster say "Your code doesn't work on my 8086", thenwe can talk, but other than that you are just wasting time arguing a perfectly valid answer because... well, only God knows! You are talking to someone who still coded on a 8086 (just for the record - I still have one at home). – Mecki Nov 16 '16 at 16:54
  • @Olaf Facts are: (1) Code using `[u]intptr_t` is not guaranteed to be portable among ISO conform compilers. (2) Code using `ptrdiff_t` is portable among all ISO conform compilers. (3) No compiler that I am aware of and that is ISO conform (and that may even have a `[u]intptr_t` data type) has a `ptrdiff_t` type where not all possible pointers would fit. The fact, that this could *theoretically* exist (which I still doubt as it makes no sense in so many aspects, even if the standard doesn't enforce it) is just like pink elephants could theoretically exist, when I said they are gray. – Mecki Nov 16 '16 at 17:04
  • 1
    1-2) Using `ptrdiff_t` is? Wow, theat's quite a false statement. At least you are guaranteed to get an error message if `(u)intptr_t` is not available. Which is no way guaranteed for the other types. 3) You should do some embedded programming then. Btw: That's the vast majority of systems. And I know about at least **one** pink elephant. – too honest for this site Nov 16 '16 at 17:22
  • @Olaf I also do embedded programming, I do that very often and I never had a problem with `ptrdiff_t`. Okay, how about that: Show me an ISO compiler for any platform of your choice, where casting a pointer to `ptrdiff_t` and back to a pointer will not result in the same pointer as before. Just one, and I take everything back, you are right, I fix my reply. If you can't, please refrain from commenting this question as then you are nitpicking and not helpful at all and SO is all about being helpful. – Mecki Nov 16 '16 at 19:10
  • @Mecki: I don't see any sense fighting wilfull ignorance. There are indeed quite some compilers which do, let alone there is absolutely no use **not** to use the types specifically designated to this. But comfortably, you ignored my other - much more relevant issues. I'm done here, but I will not stop commenting incorrect answers at **my** will. – too honest for this site Nov 16 '16 at 19:17
0

Try typecasting each address to void *

long int distance = (void *)&a - (void *)&data[5];

As others will point out, this is dangerous and undefined, but if you're just exploring how memory works, it should be fine.

Forrest
  • 236
  • 1
  • 7
  • 1
    Subtracting `void *` is UB. – too honest for this site Nov 16 '16 at 12:18
  • 1
    @Olaf It is, I believe, not UB. It is a *constraint violation,* which a conformant compiler must diagnose at compile time (the constraint is that it shall hold that "both operands are pointers to qualified or unqualified versions of compatible **complete object types.")** This constraint is also the reason the OP cannot compile (and hence not run). Implementations are free to permit this as an extension, and in fact two which are widely used do, gcc and icc. The result does not, of course, expose undefined behavior. – Peter - Reinstate Monica Nov 16 '16 at 13:24
  • @Olaf As a clarification to my last comment: Re "The result does not, of course, expose undefined behavior": As long as they point into the same array. – Peter - Reinstate Monica Nov 16 '16 at 13:33
  • @Olaf would you suggest type casting to (char *) instead then? I'm simply trying to provide an option for the OP to explore how his computer is storing variables. As I point out it's dangerous, but the value lies in understanding your computer. – Forrest Nov 16 '16 at 20:28
  • 1
    @ForrestKoch: Problem does not change by a cast. And there is no knowledge gained in seeing the address difference of two **specific** variables for a **specific** example, a **specific** implementation, **specific** optimisation setting, a **specific** compiler version, a **specific** architecture, ... A good introductory book about compiler construction would gain way more knowledge. – too honest for this site Nov 16 '16 at 22:09
  • @PeterA.Schneider: As I already wrote elsewhere: There is no need for a constraint violation the compiler does not generate code (which then invokes UB). The only requirement is to emit a diagnostic message. – too honest for this site Nov 16 '16 at 22:15
0

This is because pointer arithmetic is about offsets. For example, if you have an array and a pointer to that array like:

int array[3] = { 1, 2, 3};
int *ptr = array;

and then you increment ptr, you expect next value from the array, e.g. array[0] after array[1], no matter what type is stored in that. So when you substract pointers you don't get e.g. bytes, but offset.

Don't substract pointers that are not the part of the same array.

Vel
  • 524
  • 3
  • 11
0

The size of int and size of char pointers are different.In a system where int size is 4 bytes if you will do int_pointer++ it will increase address by 4 bytes while it will increment address by 1 byte in case of char_ptr. Hence you might be getting error.

user2879844
  • 189
  • 6
  • Ok I was aware I could get some error in calculation, but I though I could get some result from the difference instead of getting that compilation error – fedemengo Nov 17 '16 at 16:09