Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > void * arithmetic

Reply
Thread Tools

void * arithmetic

 
 
Balban
Guest
Posts: n/a
 
      02-11-2010
Hi,

On my compiler (gcc), if I add an integer value to a void pointer the
integer is interpreted as signed instead of unsigned. Is this expected
behavior?

Thanks,

Bahadir
 
Reply With Quote
 
 
 
 
Seebs
Guest
Posts: n/a
 
      02-11-2010
On 2010-02-11, Balban <(E-Mail Removed)> wrote:
> On my compiler (gcc), if I add an integer value to a void pointer the
> integer is interpreted as signed instead of unsigned. Is this expected
> behavior?


There is no expected behavior, pointer arithmetic is not defined at all
for void pointers.

That said, I don't understand how you're making the distinction. Imagine
that you have a 32-bit integer of some unspecified type, and it has the
value 0xFFFFFFFF, and you add it to a 32-bit pointer. It is going to do
the same thing whether it's signed or unsigned.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      02-11-2010
Seebs <(E-Mail Removed)> writes:
> On 2010-02-11, Balban <(E-Mail Removed)> wrote:
>> On my compiler (gcc), if I add an integer value to a void pointer the
>> integer is interpreted as signed instead of unsigned. Is this expected
>> behavior?

>
> There is no expected behavior, pointer arithmetic is not defined at all
> for void pointers.
>
> That said, I don't understand how you're making the distinction. Imagine
> that you have a 32-bit integer of some unspecified type, and it has the
> value 0xFFFFFFFF, and you add it to a 32-bit pointer. It is going to do
> the same thing whether it's signed or unsigned.


A signed 32-bit integer cannot have the value 0xFFFFFFFF.

Do you mean 0xFFFFFFFF to refer to a certain bit pattern rather than a
value?

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      02-11-2010
On 2010-02-11, Keith Thompson <(E-Mail Removed)> wrote:
> A signed 32-bit integer cannot have the value 0xFFFFFFFF.
>
> Do you mean 0xFFFFFFFF to refer to a certain bit pattern rather than a
> value?


Er, yeah. I meant "representation", specifically.

I'm off my brain all this week, I think, came down with a cold and been
sleeping funny hours.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
bartc
Guest
Posts: n/a
 
      02-11-2010

"Keith Thompson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Seebs <(E-Mail Removed)> writes:
>> On 2010-02-11, Balban <(E-Mail Removed)> wrote:
>>> On my compiler (gcc), if I add an integer value to a void pointer the
>>> integer is interpreted as signed instead of unsigned. Is this expected
>>> behavior?

>>
>> There is no expected behavior, pointer arithmetic is not defined at all
>> for void pointers.
>>
>> That said, I don't understand how you're making the distinction. Imagine
>> that you have a 32-bit integer of some unspecified type, and it has the
>> value 0xFFFFFFFF, and you add it to a 32-bit pointer. It is going to do
>> the same thing whether it's signed or unsigned.

>
> A signed 32-bit integer cannot have the value 0xFFFFFFFF.


Seems to work though:

#include <stdio.h>
#include <limits.h>

int main(void){
signed int a=0xFFFFFFFF;

printf("Bits = %d\n",(sizeof a)*CHAR_BIT);
printf("A = %X\n",a);
}

--
Bartc

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      02-11-2010
"bartc" <(E-Mail Removed)> writes:
> "Keith Thompson" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Seebs <(E-Mail Removed)> writes:
>>> On 2010-02-11, Balban <(E-Mail Removed)> wrote:
>>>> On my compiler (gcc), if I add an integer value to a void pointer the
>>>> integer is interpreted as signed instead of unsigned. Is this expected
>>>> behavior?
>>>
>>> There is no expected behavior, pointer arithmetic is not defined at all
>>> for void pointers.
>>>
>>> That said, I don't understand how you're making the distinction. Imagine
>>> that you have a 32-bit integer of some unspecified type, and it has the
>>> value 0xFFFFFFFF, and you add it to a 32-bit pointer. It is going to do
>>> the same thing whether it's signed or unsigned.

>>
>> A signed 32-bit integer cannot have the value 0xFFFFFFFF.

>
> Seems to work though:
>
> #include <stdio.h>
> #include <limits.h>
>
> int main(void){
> signed int a=0xFFFFFFFF;
>
> printf("Bits = %d\n",(sizeof a)*CHAR_BIT);
> printf("A = %X\n",a);
> }


Depends on what you mean by "work".

Assuming int is 32 bits on your system, initializing ``a'' with
the expression 0xFFFFFFFF does not store the value 0xFFFFFFFF
(equivalently, 4294967295) in ``a''. Instead, it stores the result
of converting 0xFFFFFFFF from unsigned int to int. That result
is implementation-defined. (It's probably -1 on your system;
it is on mine.)

Then in your printf call, you use a "%X" format, which expects a value
of type unsigned int, with an argument of type int. There's a special
rule that says you can get away with this if the value is within the
range of values representable either as int or as unsigned int, but
that's not the case here, so strictly speaking I think the behavior is
undefined. In practice, the printed result is very likely to be what
you would get by interpreting the representation of the int object
``a'' (with whatever value resulted from the conversion) as it were an
object of type unsigned int.

It's hardly surprising that the output is "A = FFFFFFFF",
but it's certainly not required, and it doesn't indicate that
you've managed to store the value 0xFFFFFFFF in ``a''. In fact,
it's simply not possible to do so.

(Also, you're using "%d" with a size_t argument in the first
printf call. And let me repeat my plea not to use the name "a" for
variables in small demo programs; it makes the code more difficult
to talk about. "x" or "n" would be fine.)

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
ImpalerCore
Guest
Posts: n/a
 
      02-11-2010
On Feb 11, 2:12*pm, Balban <(E-Mail Removed)> wrote:
> Hi,
>
> On my compiler (gcc), if I add an integer value to a void pointer the
> integer is interpreted as signed instead of unsigned. Is this expected
> behavior?


As other people have said, addition is not supported by the standard
using void*. gcc allows you to add to void pointers by implicitly
casting the pointer to unsigned char* (or maybe char*, I'm not really
sure) type. I actually used to do it until recently. Now I cast the
pointer before performing the addition; it plays nicer with -ansi -
pedantic.

i.e.

typedef unsigned char byte;

void* track_malloc( size_t size )
{
void* mem = NULL;
void* p = NULL;

p = malloc( size + sizeof( size_t ) );
if ( p )
{
*((size_t*)p) = size;
mem = (byte*)p + sizeof( size_t );
}

return mem;
}

void track_free( void* p )
{
void* actual_p = NULL;
size_t p_size = 0;

if ( p )
{
actual_p = (byte*)p - sizeof( size_t );
p_size = *((size_t*)actual_p);
free( actual_p );
printf( "track_free [p,size] = [%p,%u]\n", actual_p, p_size );
}
}

Best regards,
John D.

> Thanks,
>
> Bahadir


 
Reply With Quote
 
gil_johnson
Guest
Posts: n/a
 
      02-12-2010
On Feb 11, 1:12*pm, Balban <(E-Mail Removed)> wrote:
> Hi,
>
> On my compiler (gcc), if I add an integer value to a void pointer the
> integer is interpreted as signed instead of unsigned. Is this expected
> behavior?
>
> Thanks,
>
> Bahadir


I'm not an expert, but it seems to be a good idea to me. I can imagine
that you might calculate a new offset into a data structure, relative
to the current position, and have it come out negative. It would be
simpler to add the negative than force the answer to be positive and
keep track of addition vs subtraction.
As others have noted, the behavior is not specified by the standard, I
think this may be an example of "Do the least surprising thing."
Gil
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      02-12-2010
Balban <(E-Mail Removed)> writes:
> On my compiler (gcc), if I add an integer value to a void pointer the
> integer is interpreted as signed instead of unsigned. Is this expected
> behavior?


I don't think that's what's happening.

As has already been mentioned, arithmetic on void* is a gcc-specific
extension; in standard C, it's a constraint violation, requiring a
diagnostic.

But the same thing applies to arithmetic on char*, which is well
defined by the standard.

Adding a pointer and an integer (p + i) yields a new pointer value
that points i elements away from where p points. For example, if p
points to the element 0 of an array, then (p + 3) points to element 3
of the same array. If p points to element 7 of an array, then (p - 2)
points to element 5 of the same array.

It would have been helpful if you had shown us an example of what
you're talking about. But suppose we have:

char arr[10];
char *p = arr + 5;
int i = -1;
unsigned int u = -1;

Let's assume a typical system where int and pointers are 32 bits.

So p points to arr[5]. The expression (p + i) points to arr[4].
But consider (p + u).

Since u is unsigned, it can't actually hold the value -1. During
initialization, that value is implicitly converted from signed
int to unsigned int, and the value stored in u is 4294967295.
In theory, then, (p + u) would point to arr[4294967300], which
obviously doesn't exist. So the behavior is undefined, if you try
to evaluate (p + u), anything can happen.

What probably will happen on typical modern systems is that the
addition will quietly wrap around. Let's assume that pointer values
are represented as 32-bit addresses that look like unsigned integers
(nothing like this is required by the standard, but it's a typical
implementation), and let's say that arr is at address 0x12345678.
Then p points to address 0x1234567d, and (p + 4294967295) would
theoretically point to address 0x11234567c. But this would require 33
bits, and we only have 32-bit addresses. Typically, an overflowing
addition like this will quietly drop the high-order bit(s) yielding an
address of 0x1234567c -- which just happens to be the address of
arr[4].

So you initialized u with the value -1, computed (p + u), and
got the same result you would have gotten for (p + (-1)). But in
the process, you generated an intermediate result that was out of
range, resulting in undefined behavior. (This is really the worst
possible consequence of undefined behavior: having your program
behave exactly as you expected it to. It means your code is buggy,
but it's going to be very difficult to find and correct the problem.)

This kind of thing is very common with 2's-complement systems. The
2's-complement representation is designed in such a way that addition
and subtraction don't have to care whether the operands are signed or
unsigned. But you shouldn't depend on this. The behavior of addition
and subtraction operations, either on integers or on pointers, is well
defined only when the mathematical result is within the required
range. Adding 0xFFFFFFFF to a pointer can appear to work "correctly",
as if you had really added -1, but it's better to just add a signed
value -1 in the first place.

Even if your code never runs on anything other that the system you
wrote it for, an optimizing compiler may assume that no undefined
behavior occurs. For example, if you write (p + u), it can assume
that p is in the range 0 to 5, and perform optimizations that depend
on that assumption.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Ike Naar
Guest
Posts: n/a
 
      02-12-2010
In article <(E-Mail Removed)>,
Keith Thompson <(E-Mail Removed)> wrote:
> [snip]
> char arr[10];
> char *p = arr + 5;
> int i = -1;
> unsigned int u = -1;
> [snip]
>Even if your code never runs on anything other that the system you
>wrote it for, an optimizing compiler may assume that no undefined
>behavior occurs. For example, if you write (p + u), it can assume
>that p is in the range 0 to 5, and perform optimizations that depend

^
Is this a mis-typed ``u'' ?
>on that assumption.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
What is the difference between void proba(); and void proba(void); ??? PencoOdStip@gmail.com C++ 1 05-23-2007 07:12 PM
what is the difference, void func(void) and void fucn() noblesantosh@yahoo.com C Programming 5 07-22-2005 04:38 PM
"void Method()" vs "void Method(void)" Ollej Reemt C++ 7 04-22-2005 03:47 AM
Usual Arithmetic Conversions-arithmetic expressions joshc C Programming 5 03-31-2005 02:23 AM
`void **' revisited: void *pop(void **root) Stig Brautaset C Programming 15 10-28-2003 09:03 AM



Advertisments