increment of void *

B

Burne C

I have something confused in my mind

void *search_address = 0;

[something...]

++search_address;

/* The compiler complain that "void *" is unknown size.
OK, I changed the code
*/
void *search_address = 0;

[something...]

++(char*)search_address;

I try to cast it to char* before the increment, is it illegal here ?


Thanks in advance.
 
J

Jeremy Yallop

Burne said:
++(char*)search_address;

I try to cast it to char* before the increment, is it illegal here ?

Yes. The result of a cast is a ("temporary") value rather than an
object, so the ++ operator can't be applied to it.

Jeremy.
 
N

Nick Austin

I have something confused in my mind
[snip]

void *search_address = 0;

[something...]

++(char*)search_address;

I try to cast it to char* before the increment, is it illegal here ?

No. Because that's equivalent to
(char *)search_address = (char *)search_address + 1;

ANSI C does not allow an lvalue to be cast.

This will work:
search_address = (char *)search_address + 1;

Nick.
 
M

Martijn

ANSI C does not allow an lvalue to be cast.
This will work:
search_address = (char *)search_address + 1;

In response to that: is this cast illegal too?

/* ul is unsigned long containing pointer to string */
if ( (char*)ul == NULL )

Because although I am comfortable with both, I am unsure whether to use that
or

if ( ul == (long)NULL )

Thanks,
 
R

Richard Heathfield

Burne said:
I have something confused in my mind

void *search_address = 0;

[something...]

++search_address;

/* The compiler complain that "void *" is unknown size.

It is right so to do. If it doesn't know how big the object is (that
search_address points to), then it can't know how to point to the next
object of that type.
OK, I changed the code
*/
void *search_address = 0;

[something...]

++(char*)search_address;

I try to cast it to char* before the increment, is it illegal here ?

Casting doesn't return an lvalue, so it's wrong here. You can, however, do
this (provided you know for sure it's chars that you're pointing to):

{
char *tmp = search_address;
search_address = ++tmp;
}
 
D

Derk Gwen

# I have something confused in my mind
#
# void *search_address = 0;
#
# [something...]
#
# ++search_address;
#
# /* The compiler complain that "void *" is unknown size.
# OK, I changed the code
# */
# void *search_address = 0;
#
# [something...]
#
# ++(char*)search_address;

Perhaps
++(*((char**)(&search_address)))

Perhaps you can type search_address with a type appropriate to what you are
searching for. If you have to go through such convolutions to express your
program, perhaps you need to reconsider how you've written your program.
 
R

Richard Heathfield

(That's not quite right. What your correspondent meant to say is that a cast
does not result in an lvalue.)

(Note that he casts an lvalue here! Quite correctly, too.)
In response to that: is this cast illegal too?

/* ul is unsigned long containing pointer to string */
if ( (char*)ul == NULL )

The cast is legal and unnecessary.
Because although I am comfortable with both, I am unsure whether to use
that or

if ( ul == (long)NULL )

This isn't as good as if((char *)ul == NULL) (in my opinion), and neither is
as good as:

if(ul == NULL)

which combines elegance with simplicity.

For the record, I'd probably write this as

if(NULL == ul)

on the grounds that I occasionally type = rather than == and I do like my
compiler to warn me about such typos when possible.
 
K

Keith Thompson

Or, nearly equivalently, C does not allow a cast expression to be the
target of an assignment. The following:

(char*)foo = some_value;

is illegal for the same reason that

(foo + 1) = some_value;
In response to that: is this cast illegal too?

/* ul is unsigned long containing pointer to string */
if ( (char*)ul == NULL )

Because although I am comfortable with both, I am unsure whether to use that
or

if ( ul == (long)NULL )

There are no lvalues in either form (you're comparing, not assigning),
so this isn't really relevant to the original question.

Given that ul is an unsigned long containing a pointer to a string,
I'd go with the first one. The second form is doing an integer
comparison of two pointer values; this is likely to work as expected
for an equality comparison, but I've worked on systems where it could
fail badly for "<" and other comparisons. (And the second form
compares an unsigned long to a signed long; that might be ok, but I'm
not going to spend the brain cells necessary to convince myself.)

Having said that, you really shouldn't be comfortable with the idea of
storing a pointer in an unsigned long variable. If you want ul to
contain a pointer to a string, why didn't you declare it as char*?

There is no guarantee that the types char* and unsigned long are even
the same size; either could be larger than the other. And although
it's legal to convert between integer types and pointer types, there
are very few guarantees about the semantics.

What problem are you trying to solve? If the answer is storing a
string pointer in an integer variable, you're very likely asking the
wrong question.
 
A

Arthur J. O'Dwyer

Arthur J. O'Dwyer said:
# I have something confused in my mind
#
# void *search_address = 0;
#
# [something...]
#
# ++search_address;
#
# /* The compiler complain that "void *" is unknown size.
# OK, I changed the code
# */
# void *search_address = 0;
#
# [something...]
#
# ++(char*)search_address;

Perhaps
++(*((char**)(&search_address)))

Won't necessarily work, and a very good compiler will even warn
you about the dubious cast. (void**) and (char**) are not
necessarily compatible.

Well... void * and char * are guaranteed to have the same
representation, so this is probably OK.

void * is guaranteed, IIRC, to have the same representation as
"a pointer to a character type" or words to that effect. As far
as I know, it's still up in the air whether that means "all
character types", "plain character type", or "some character type".

And it's *still* not relevant, because (void **) and (char **) are
not compatible types. Sure, it'll work on my compiler, and yours,
and Dan Pop's, but it won't work on the DS9000. :) And since there's
a perfectly legal and valid way to do it in plain C, there's absolutely
no reason to do it Derk's way.

-Arthur
 
M

Martijn

This isn't as good as if((char *)ul == NULL) (in my opinion), and
neither is as good as:

if(ul == NULL)

My compiler complains about this (unless I do a cast, or turn off the
appropriate warning for that section, so that's why I'm casting. Guess I'm
shutting the compiler up ;)
 
A

Arthur J. O'Dwyer

[Richard Heathfield wrote:]
This isn't as good as if((char *)ul == NULL) (in my opinion), and
neither is as good as:

if(ul == NULL)

My compiler complains about this (unless I do a cast, or turn off the
appropriate warning for that section, so that's why I'm casting. Guess I'm
shutting the compiler up ;)

Well, it depends on the type of 'ul'. If 'ul' is of pointer type, then
Richard's is the preferred way to do the comparison. If 'ul' is not
of pointer type, then you should not be comparing it to the pointer
value NULL. Perhaps if you posted some code, someone could tell you
what you're doing wrong.

-Arthur
 
D

Dan Pop

In said:
I have something confused in my mind

void *search_address = 0;

[something...]

++search_address;

If you need to increment it, then it shouldn't have been a void pointer
in the first place. void has no size, therefore it is impossible to
perform pointer arithmetic on void pointers.
/* The compiler complain that "void *" is unknown size.
OK, I changed the code
*/
void *search_address = 0;

[something...]

++(char*)search_address;

I try to cast it to char* before the increment, is it illegal here ?

The first rule of programming is "know what you're doing". If you don't
know, either check it in your favourite C book or don't do it.

BTW, your particular question is addressed by the FAQ.

Dan
 
D

Dan Pop

In said:
void * is guaranteed, IIRC, to have the same representation as
"a pointer to a character type" or words to that effect. As far
as I know, it's still up in the air whether that means "all
character types", "plain character type", or "some character type".

This is a bug in the standard. All character pointers are supposed to
have the same representation, but the standard fails to say it. Ditto
for pointers to the signed and unsigned "flavour" of integer types.

Dan
 
M

Martijn

Keith said:
The original article said that ul is an unsigned long holding a string
pointer.

[snip]
The real problem is that storing a string pointer in an unsigned long
is almost certainly a bad idea. The OP was asking how to get his
compiler to stop telling him he's doing something dumb. The correct
answer is listen to what the compiler is saying, and store values in
variables of appropriate type.

Rewriting the Windows API/kernel (I know, OT here) is not something I had
planned in the near future and when it sends messages, it uses longs to
store some of its arguments, which are more often than not pointers.
Extracted from the header files:

basetsd.h:
typedef long LONG_PTR, *PLONG_PTR;

windef.h:
typedef LONG_PTR LPARAM;

LPARAM is the type of one of the arguments sent along with each message. So
it's actually a signed long.

Thanks for the help everyone,
 
R

Richard Heathfield

Keith Thompson wrote:

The original article said that ul is an unsigned long holding a string
pointer.

Oops. My apologies for not spotting that.

The real problem is that storing a string pointer in an unsigned long
is almost certainly a bad idea.

s/almost // /* IMHO */

<snip>
 
P

pete

Martijn said:
So it's actually a signed long.

Then it should be compared against an integer form of zero
instead of NULL.

These forms are valid for both pointer sl and signed long sl:
if (sl == 0)
if (!sl)
if (sl == 0l)
 
K

Keith Thompson

pete said:
Then it should be compared against an integer form of zero
instead of NULL.

Well, maybe. The signed long object is actually holding a pointer
value. As we've just learned, this ugliness is imposed by Windows, so
the OP is stuck with it.

Comparing it against an integer form of 0 assumes that a null pointer
is represented as all-bits-zero -- which is probably a safe assumption
in this context, but it also hides the fact that you're really doing a
pointer comparison.

In another article, Martijn says that the definitions he's stuck with
are:

typedef long LONG_PTR, *PLONG_PTR;
typedef LONG_PTR LPARAM;

(So MS is willing to use a pointer type for a pointer to pointer to
long, but not for a pointer to long. Dumb *and* inconsistent.)

Given that, I'd probably declare my own macro for a null LONG_PTR:

#define LONG_PTR_NULL ((LONG_PTR)NULL)

and compare against that:

LONG_PTR obj = some_value;
if (obj == LONG_PTR_NULL) {
...
}

But first I'd look through the headers and see whether MS has already
provided such a macro.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,297
Latest member
EngineerD

Latest Threads

Top