-2

I have a return value from a library which is a void pointer. I know that it points to a short int; I try to obtain the int value in the following way (replacing the function call with a simple assignment to a void *):

short n = 1;
void* s = &n;
int k = *(int*)s;

I try to cast a void pointer that points to an address in which there is a short and I try to cast the pointer to point to an int and when I do so the output becomes a rubbish value. While I understand why it's behaving like that I don't know if there's a solution to this.

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
muhzi
  • 119
  • 2
  • 14
  • 7
    The solution is to not do the cast. – juanchopanza Dec 18 '17 at 21:17
  • 2
    `int k = *(short*)s`? – Stephan Lechner Dec 18 '17 at 21:17
  • @juanchopanza how do you mean? – muhzi Dec 18 '17 at 21:18
  • I have a problem in which something like this arises – muhzi Dec 18 '17 at 21:18
  • @airomyst I mean don't do this cast: `(int*)s`. – juanchopanza Dec 18 '17 at 21:19
  • 1
    Casting *anything* to a `void*` (and back) is often the result of bad design (as you loose all type information and safety). Why do you need to do this? – UnholySheep Dec 18 '17 at 21:21
  • \*(int\*)s is trying to dereference a 4-byte address but the variable n occupies only 2-bytes so it's not surprising it doesn't work. – dsp_user Dec 18 '17 at 21:22
  • @juanchopanza I see your point yes. but as I said I have a similar problem in which I kinda need to do this. or do you mean I can't get away with it? – muhzi Dec 18 '17 at 21:22
  • The size of a `short` and `int` are different and result in a bad conversion @UnholySheep is right `void*` are bad, but if you use it make sure it is done correctly. – Jake Freeman Dec 18 '17 at 21:22
  • When you cast an int pointer from a short, it will pick up two more bytes, (on most systems), as part of the value that have nothing to do with the original short. Hence, you get a garbage value. The compiler won't 'fix' this for you as it will simply do what you ask of it. – lakeweb Dec 18 '17 at 21:23
  • I have a function that returns a void pointer and I would need to cast the value accordingly. – muhzi Dec 18 '17 at 21:25
  • Is that function from an external library/API you cannot modify? If yes then it needs to somehow give you information about what data type this pointer is pointing to, a `void*` itself does not hold any information about that – UnholySheep Dec 18 '17 at 21:27
  • 1
    @airomyst you can only cast it back to it's original type not whatever type you would like it to be. Any other cast to an unrelated type is undefined behaviour. – Richard Critten Dec 18 '17 at 21:27
  • @UnholySheep yes that is the case. – muhzi Dec 18 '17 at 21:31
  • @RichardCritten I understand it is an undefined behavior I was asking if I can get around it and to solve my problem. – muhzi Dec 18 '17 at 21:31
  • airomyst, is the return from this function documented? Sounds like it may be... – lakeweb Dec 18 '17 at 21:34
  • The whole discussion above reminds me of an old joke and patient comes to see a doctor and says 'Doctor, it hurts me very much when I do this, what can you advise?', - and stretches his body in a very twisted way. To that doctor replies: 'I advise you not to do that.' – SergeyA Dec 18 '17 at 21:34
  • @SergeyA Well, I might have a different view. anyway, I got what I needed. thanks. – muhzi Dec 18 '17 at 21:38
  • @airomyst -- That API function is useless if the documentation doesn't tell you what the real type is behind that `void *`. – PaulMcKenzie Dec 18 '17 at 21:39
  • I changed the question to include what you added in your comments (which you should do yourself next time ;-) ). Feel free to revert if you don't like it. You may also want to edit in the actual function call and (if it's not too complicated) the original function declaration from a header. Generally you get the best answers if you keep as close to the original problem as possible. – Peter - Reinstate Monica Dec 18 '17 at 21:53
  • @PeterA.Schneider thank you for the tip :) – muhzi Dec 18 '17 at 21:57

4 Answers4

6

If the problem you are dealing with truly deals with short and int, you can simply avoid the pointer and use:

short n = 1;
int k = n;

If the object types you are dealing with are different, then the solution will depend on what those types are.

Update, in response to OP's comment

In a comment, you said,

I have a function that returns a void pointer and I would need to cast the value accordingly.

If you know that the function returns a void* that truly points to a short object, then, your best bet is:

 void* ptr = function_returning_ptr();
 short* sptr = reinterpret_cast<short*>(ptr);
 int k = *sptr;

The last line work since *sptr evaluates to a short and the conversion of a short to an int is a valid operation. On the other hand,

 int k = *(int*)sptr;

does not work since conversion of short* to an int* is not a valid operation.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • You could elaborate that the conversion short -> int is legit and fairly commonplace, while the conversion short* -> int* is neither. – Peter - Reinstate Monica Dec 18 '17 at 21:35
  • Can you explain why *static_cast* is not used in place of *reinterpret_cast*? This post suggests that a *static_cast* should generally be preferred in void* conversions https://stackoverflow.com/questions/573294/when-to-use-reinterpret-cast – dsp_user Dec 18 '17 at 21:39
  • @dsp_user, I didn't draw the same conclusion from the linked post as you did. Either seems to be a good option to convert between pointers. – R Sahu Dec 18 '17 at 21:54
  • Well, even a C-style cast will do though some people object to using C-style conversions in C++. I don't ;) – dsp_user Dec 18 '17 at 21:58
  • @dsp_user, have a look at https://stackoverflow.com/questions/103512/why-use-static-castintx-instead-of-intx. – R Sahu Dec 18 '17 at 22:06
  • @SergeyA Why would this code not compile with `static_cast`? – user3366592 Dec 18 '17 at 22:22
  • Yes, when objects (classes) are involved *static_cast* does provide compile-time type checks. – dsp_user Dec 18 '17 at 22:25
  • @user3366592 because I was wrong, I somehow misread the question :) – SergeyA Dec 18 '17 at 22:27
1

Your code is subject to undefined behavior, as it violates the so-called strict aliasing rules. Without going into too much detail and simplifying a bit, the rule states that you can not access an object of type X though a pointer to type Z unless types X and Z are related. There is a special exception for char pointer, but it doesn't apply here.

In your example, short and int are not related types, and as such, accessing one through pointer to another is not allowed.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
0

The size of a short is only 16 bits the size of a int is 32 bits ( in most cases not always) this means that you are tricking the computer into thinking that your pointer to a short is actually pointing to an integer. This causes it to read more memory that it should and is reading garbage memory. If you cast s to a pointer to a short then deference it it will work.

   short n = 1;
   void* s = &n;
   int k = *(short*)s;  
Marcus Karpoff
  • 451
  • 5
  • 16
  • `short` is definitely not 8 bits, that would violate the C++ standard (which states that `short` is *at least* 16 bits) – UnholySheep Dec 18 '17 at 21:22
  • `short` is **at least** 16 bits, and `int` is **at least** 16 bits. They may well be the same size, and on many systems they are. – Pete Becker Dec 18 '17 at 22:18
0

Assuming you have 2 byte shorts and 4 byte ints, There's 3 problems with casting pointers in your method.

First off, the 4 byte int will necessarily pick up some garbage memory when using the short's pointer. If you're lucky the 2 bytes after short n will be 0.

Second, the 4 byte int may not be properly aligned. Basically, the memory address of a 4 byte int has to be a multiple of 4, or else you risk bus errors. Your 2 byte short is not guaranteed to be properly aligned.

Finally, you have a big-endian/little-endian dependency. You can't turn a big-endian short into a little-endian int by just tacking on some 0's at the end.

In the very fortunate circumstance that the bytes following the short are 0, AND the short is integer aligned, AND the system uses little-endian representation, then such a cast will probably work. It would be terrible, but it would (probably) work.


The proper solution is to use the original type and let the compiler cast. Instead of int k = *(int*)s;, you need to use int k = *(short *)s;

QuestionC
  • 10,006
  • 4
  • 26
  • 44