0
int add(int a, int b)
{
  return (int)&(((char *)a)[b]);
}

Why am I supposed to cast a to a char * and not int *?

I'm trying to understand this code fully but I can't, so if it's easy to you, please, provide a simple English explanation.

Michael
  • 876
  • 9
  • 29

4 Answers4

6

The idea is that an array is simply an addition of a pointer with an index. If a is a char [] (or char *) and b is an integer, then a[b] is the value at the address a+b. This code is casting a as a pointer, indexing it with b, and finding the address, which should equal a+b.

But in the real world, don't ever ever ever do this.

Graeme Perrow
  • 56,086
  • 21
  • 82
  • 121
0

To make it compile you need to turn it into valid c++. Pointers are incompatible with integers, but the distance between two pointers is an integer type:

#include <iterator>

int add(int a, int b)
{
    auto p = (char *)0;
    auto p2 = &(&p[a])[b];

    return static_cast<int>(std::distance(p, p2));
}

Disclaimer: I do not endorse this product or service.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • FYI the code in the original question compiles (as C) and works with Visual Studio 2013. – Graeme Perrow Dec 09 '16 at 12:49
  • In the calculation of `p2`, you have the expression `p[a]`. That is undefined behaviour because `p` is a null pointer. – Martin Bonner supports Monica Dec 09 '16 at 12:49
  • @MartinBonner the expression is `&p[a]` - After the c-style cast, p is not a null pointer, it is simply a pointer to char. Whether taking the address of p[a] is UB or not I'm afraid I don't know the standard deeply enough to comment. – Richard Hodges Dec 09 '16 at 13:03
  • @MartinBonner I do believe that it's not UB. I've investigated this some time ago, but don't remember the standard quote. The expression being an argument to the addressof operator is crucial - it is not evaluated. – eerorika Dec 09 '16 at 13:08
  • @RichardHodges: `p` is not a *null pointer constant*, but it *is* a pointer (specifically, pointer to char) which is null. If you write `*p`, that is undefined behaviour. – Martin Bonner supports Monica Dec 09 '16 at 13:48
  • @user2079303: Oooh! You may be right. I can't remember whether it is C or C++ where that is true though. – Martin Bonner supports Monica Dec 09 '16 at 13:49
0

Why am I supposed to cast a to a char * and not int *?

To clarify for the readers of the question, you aren't supposed to use code like this at all. But let us assume that you're competing in the ioccc (is there a C++ variant of this competition?), in which case this may be exactly what you're supposed to do.

So, to answer the question, it is because pointer arithmetic is scaled by the size of the pointed object. If you used int*, then b would be scaled by sizeof(int). Since you don't want to scale either operand of an addition, you scale with 1 (the multiplicative identity) which happens when the pointed type has the size 1 - which by definition char has.

P.S. The program is ill-formed and may fail to compile on standard compliant compilers.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • 1
    There is no ioc++cc. There would be no challenge in writing unreadable C++. – Martin Bonner supports Monica Dec 09 '16 at 12:51
  • Thanks for the explanation. I didn't ask this question from my main acc because i knew the reaction would be. But you are right, this is for a competition. –  Dec 09 '16 at 12:54
  • @Tracy I think that stating that the intention is to write obfuscated code, and that this is not for production use might have softened the reaction. Not all readers of this site will understand implicitly. Some of them (and people who don't want such people to become confused) may wish that this would be voted into the oblivion. – eerorika Dec 09 '16 at 13:02
0

Let us take an example with a as 100 and b as 103

  1. (char *)a --> this typecasts a as a pointer. So a will be considered as a pointer.
  2. ((char *)a)[b] --> this is 100[103], i.e. it gives the value at the location (100 + 103)
  3. &(((char *)a)[b] --> this gives the address of the above value, i.e. it gives 203.
  4. (int)&(((char *)a)[b] --> the final typecast to int will convert the address above to an integer value as required by the return value of the function.

This will only work with char* typecast in step 2. If you use an int* typecast there, the sum that you get at step 3 will be 100 + 4*103 i.e. 512

Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31
  • 2
    "this is 100[103]" should be "this is undefined behavior". – Lundin Dec 09 '16 at 12:48
  • `a` is a character pointer at that stage. so `a[b]` is well defined. – Rishikesh Raje Dec 09 '16 at 12:50
  • Rishikesh, please be a bit more precise. In point 2, the value is never taken (would segfault); in point 4 there is no "char value", just an address. – Paul Ogilvie Dec 09 '16 at 12:53
  • 1
    6.5.2.1 Array subscripting "The definition of the subscript operator [] is that `E1[E2]` is identical to `(*((E1)+(E2)))`." So the addition operator is used implicitly, and then this applies, 6.5.6: "If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined." So you answer isn't correct, because it pretends that the code has predictable behavior. – Lundin Dec 09 '16 at 13:00
  • @RishikeshRaje why it's added?i mean, 100[103] why 100+103?? –  Dec 09 '16 at 18:06
  • @Tracy It is added because that is how the address of an array works. `a[b]` is equal to `*(a+b)`. As per pointer addition, when you add 1, the address increased by the size of the type. In this case, it is a character. So the address increases by `103` – Rishikesh Raje Dec 12 '16 at 04:53