Velocity Reviews - Computer Hardware Reviews

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

Reply
Thread Tools

void * arithmetic

 
 
Balban
Guest
Posts: n/a
 
      02-12-2010
On Feb 12, 4:39*am, Keith Thompson <(E-Mail Removed)> wrote:
> 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:
>


Thanks to all who answered. I have the following code which had
unexpected behavior for me:


#define PAGER_VIRTUAL_START 0xa039d000

/*
* Find the page's offset from virtual start, add it to membank
* physical start offset
*/
void *virt_to_phys(void *v)
{
return v - PAGER_VIRTUAL_START + membank[0].start;
}

membank[0].start is an unsigned long of value 0x100000

Now if I pass v argument with a value of 0xa039d000 to this function,
I get a return value of 0x400000. Note v = 0xa039d000 means that v and
PAGER_VIRTUAL_START would cancel out and return value would be the
value of membank[0].start which is 0x100000

Below is the corrected code.

/*
* Find the page's offset from virtual start, add it to membank
* physical start offset
*/
void *virt_to_phys(void *v)
{
unsigned long vaddr = (unsigned long)v;

return (void *)(vaddr - PAGER_VIRTUAL_START +
membank[0].start);
}

This one behaves as I expected, returning 0x100000.


Thanks,

Bahadir



 
Reply With Quote
 
 
 
 
Seebs
Guest
Posts: n/a
 
      02-12-2010
On 2010-02-12, Balban <(E-Mail Removed)> wrote:
> Thanks to all who answered. I have the following code which had
> unexpected behavior for me:


> #define PAGER_VIRTUAL_START 0xa039d000


> /*
> * Find the page's offset from virtual start, add it to membank
> * physical start offset
> */
> void *virt_to_phys(void *v)
> {
> return v - PAGER_VIRTUAL_START + membank[0].start;
> }


> membank[0].start is an unsigned long of value 0x100000


Hmm.

> Now if I pass v argument with a value of 0xa039d000 to this function,
> I get a return value of 0x400000. Note v = 0xa039d000 means that v and
> PAGER_VIRTUAL_START would cancel out and return value would be the
> value of membank[0].start which is 0x100000


Hmm.

It does seem so, and indeed, that's the behavior I get from gcc for this
test program:

#include <stdio.h>

#define PVS 0xa039d000
unsigned long mb0s = 0x100000;

void *vtp(void *v) {
return v - PVS + mb0s;
}

int
main(void) {
printf("%p\n", vtp((void *) PVS));
return 0;
}

This produces 0x100000, as you appeared to expect. I can't see any reason
for it to yield other values, but so far as I can tell, it's equivalent to
what you described above.

> Below is the corrected code.


This code is probably less robust than you want it to be.

> void *virt_to_phys(void *v)
> {
> unsigned long vaddr = (unsigned long)v;
>
> return (void *)(vaddr - PAGER_VIRTUAL_START +
> membank[0].start);
> }


Don't use "unsigned long" -- there are real targets on which unsigned long
is smaller than a pointer.

Try:

void *
virt_to_phys(void *v)
{
unsigned char *u = v;
return u - (PAGER_VIRTUAL_START + membank[0].start);
}

Rationale:

You have a pair of unsigned long values. Do the arithmetic on those,
then use the single offset, once, on an object that is of the right type
to have defined semantics. (Obviously, semantics are not defined in
general for pointer arithmetic outside the bounds of a C object, but in
your case I think it's reasonable to assume that you have a good view of
the nature of the address space.)

If you want to do arithmetic on addresses, "unsigned char *" is nearly
always the right type. If you want to do arithmetic on addresses in
an integer type, see if your target has "intptr_t" defined, and if so,
use that. (It's been standard since C99, but implementation isn't universal;
it should be in <stdint.h> if it exists, and I think there's a feature
test macro for it.)

-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-12-2010
(E-Mail Removed) (Ike Naar) writes:
> 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.


Yes, thank you.

--
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
 
Balban
Guest
Posts: n/a
 
      02-13-2010
On Feb 12, 3:38*pm, Seebs <(E-Mail Removed)> wrote:
> On 2010-02-12, Balban <(E-Mail Removed)> wrote:
> This produces 0x100000, as you appeared to expect. *I can't see any reason
> for it to yield other values, but so far as I can tell, it's equivalent to
> what you described above.
>


It might be that it is a compiler bug then. It is a cross-compiler and
I suspect the generated assembler is not correct.

> Don't use "unsigned long" -- there are real targets on which unsigned long
> is smaller than a pointer.
>


This is going into off-topic areas but as far as I know at least in 32
and 64-bit machines unsigned long always gives the machine's
addressing size whereas unsigned int would give you the machine word
i.e. register size.

But you do have a point in that char * is fairly safe for pointer
arithmetic.

Thanks,

Bahadir
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      02-13-2010
On 2010-02-13, Balban <(E-Mail Removed)> wrote:
> This is going into off-topic areas but as far as I know at least in 32
> and 64-bit machines unsigned long always gives the machine's
> addressing size whereas unsigned int would give you the machine word
> i.e. register size.


Not always. There have been machines on which long was 32-bit and pointer
was 64-bit. Not many, perhaps, and it's arguably a pretty bad choice of
sizes, but it's been done -- that's a big part of why we have "long long".

> But you do have a point in that char * is fairly safe for pointer
> arithmetic.


And, if you really are seeing a compiler bug, this may also work around
it.

-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
 
Barry Schwarz
Guest
Posts: n/a
 
      02-13-2010
On Sat, 13 Feb 2010 14:04:06 -0800 (PST), Balban
<(E-Mail Removed)> wrote:

>On Feb 12, 3:38*pm, Seebs <(E-Mail Removed)> wrote:
>> On 2010-02-12, Balban <(E-Mail Removed)> wrote:
>> This produces 0x100000, as you appeared to expect. *I can't see any reason
>> for it to yield other values, but so far as I can tell, it's equivalent to
>> what you described above.
>>

>
>It might be that it is a compiler bug then. It is a cross-compiler and
>I suspect the generated assembler is not correct.
>
>> Don't use "unsigned long" -- there are real targets on which unsigned long
>> is smaller than a pointer.
>>

>
>This is going into off-topic areas but as far as I know at least in 32
>and 64-bit machines unsigned long always gives the machine's
>addressing size whereas unsigned int would give you the machine word
>i.e. register size.


There are many shades of gray. On IBM z-Architecture machines, a word
is 32 bits while the hardware registers are 64 bits. Furthermore,
unsigned long is 64 bits whether the addressing mode (which is under
program control) is 64 or 32 bits. (There is also a 24 bit
addressing mode for backward compatibility and unsigned long is still
64 bits.)

--
Remove del for email
 
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