Is this valid C statement?

S

s.subbarayan

Dear all,
According to standards is this valid:

char TmpPtrWriteBuffer[1000];
void* PtrWriteBuffer =(void*) TmpPtrWriteBuffer;

I had a debate with my colleagues that anything cant be typecasted to
void* though the reverse is true.But they said this is valid.
I just can't agree with them with out a valid explaination.Can any C
standard experts clarify me this?

Regards,
s.subbarayan
 
J

Joona I Palaste

s.subbarayan said:
Dear all,
According to standards is this valid:
char TmpPtrWriteBuffer[1000];
void* PtrWriteBuffer =(void*) TmpPtrWriteBuffer;
I had a debate with my colleagues that anything cant be typecasted to
void* though the reverse is true.But they said this is valid.
I just can't agree with them with out a valid explaination.Can any C
standard experts clarify me this?

You are right on this one. A pointer to anything can be assigned into a
void *, even without a cast. However, this does not mean that any void *
can always safely be assigned into any other pointer type. There might
be alignment conflicts or other, possibly implementation-dependent,
issues.
For example the following code will usually not work:

char *cp;
int *ip;
void *vp;
if (cp=malloc(1000)) {
vp = cp+1;
ip = vp;
}

Even though the code compiles nicely, it might cause errors at run-time,
because the line ip = vp; assigns a pointer value that is not properly
aligned to int into a int pointer. (This is assuming sizeof(int)>1.)
 
X

xarax

s.subbarayan said:
Dear all,
According to standards is this valid:

char TmpPtrWriteBuffer[1000];
void* PtrWriteBuffer =(void*) TmpPtrWriteBuffer;

I had a debate with my colleagues that anything cant be typecasted to
void* though the reverse is true.But they said this is valid.
I just can't agree with them with out a valid explaination.Can any C
standard experts clarify me this?

Your colleagues are correct. A pointer of type (void*)
has the same alignment requirements and internal representation
as a (char*). The symbol "TmpPtrWriteBuffer" deteriorates
to type (char*), so casting it to (void*) doesn't harm
the integrity of the pointer value. The target symbol
"PtrWriteBuffer" has type (void*), so the assignment
from (void*) to (void*) is also valid.
 
J

Joona I Palaste

Joona I Palaste said:
s.subbarayan said:
Dear all,
According to standards is this valid:
char TmpPtrWriteBuffer[1000];
void* PtrWriteBuffer =(void*) TmpPtrWriteBuffer;
I had a debate with my colleagues that anything cant be typecasted to
void* though the reverse is true.But they said this is valid.
I just can't agree with them with out a valid explaination.Can any C
standard experts clarify me this?
You are right on this one. A pointer to anything can be assigned into a
void *, even without a cast. However, this does not mean that any void *
can always safely be assigned into any other pointer type. There might
be alignment conflicts or other, possibly implementation-dependent,
issues.
For example the following code will usually not work:
char *cp;
int *ip;
void *vp;
if (cp=malloc(1000)) {
vp = cp+1;
ip = vp;
}
Even though the code compiles nicely, it might cause errors at run-time,
because the line ip = vp; assigns a pointer value that is not properly
aligned to int into a int pointer. (This is assuming sizeof(int)>1.)

Sorry, after having read xarax's reply, I have found out that I have
answered the wrong question. Yes, your colleagues are correct in that
a pointer to anything can be assigned to void * with or without a cast.
As I have shown above, the assignment back in the other direction will
not necessarily work.

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"When a man talks dirty to a woman, that's sexual harassment. When a woman talks
dirty to a man, that's 14.99 per minute + local telephone charges!"
- Ruben Stiller
 
D

Dan Pop

In said:
s.subbarayan said:
Dear all,
According to standards is this valid:
char TmpPtrWriteBuffer[1000];
void* PtrWriteBuffer =(void*) TmpPtrWriteBuffer;
I had a debate with my colleagues that anything cant be typecasted to
void* though the reverse is true.But they said this is valid.
I just can't agree with them with out a valid explaination.Can any C
standard experts clarify me this?

You are right on this one. A pointer to anything can be assigned into a
void *, even without a cast. ^^^^^^^^

You are wrong on this one. Pointers to functions cannot be converted
(either explicitly or implicitly) to pointers to void (and vice versa).
Undefined behaviour due to lack of specification in the standard.

Dan
 
S

S.Tobias

Joona I Palaste said:
answered the wrong question. Yes, your colleagues are correct in that
a pointer to anything can be assigned to void * with or without a cast.

....provided that "anything" is not a function.
 
J

Joona I Palaste

Dan Pop said:
In said:
s.subbarayan said:
Dear all,
According to standards is this valid:
char TmpPtrWriteBuffer[1000];
void* PtrWriteBuffer =(void*) TmpPtrWriteBuffer;
I had a debate with my colleagues that anything cant be typecasted to
void* though the reverse is true.But they said this is valid.
I just can't agree with them with out a valid explaination.Can any C
standard experts clarify me this?

You are right on this one. A pointer to anything can be assigned into a
void *, even without a cast. ^^^^^^^^
You are wrong on this one. Pointers to functions cannot be converted
(either explicitly or implicitly) to pointers to void (and vice versa).
Undefined behaviour due to lack of specification in the standard.

Yes, I should have realised that. Read "anything" as "any object type"
and it will work. Thanks for the correction, Dan.

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"A bee could, in effect, gather its junk. Llamas (no poor quadripeds) tune
and vow excitedly zooming."
- JIPsoft
 
K

kal

Joona I Palaste said:
Sorry, after having read xarax's reply, I have found out that I have
answered the wrong question. Yes, your colleagues are correct in that
a pointer to anything can be assigned to void * with or without a cast.
As I have shown above, the assignment back in the other direction will
not necessarily work.

int *ptr_to_int = malloc(100 * sizeof *ptr_to_int);
 
K

kal

Joona I Palaste said:
What's that supposed to mean? I said "will not necessarily work", not
"will never work".

1. A pointer to void can be converted to and from a pointer to
any object type (a function is not an object.)

Whether the converted pointer will be properly aligned for
it to be useful is another question entirely.

2. A pointer to any object type can be converted to a pointer
to character. The resulting character pointer is always
correctly aligned (see 6.3.2.3 (7).)

Since the OP's question involved conversion between "void *" and
"char *", it SHOULD ALWAYS work.


Now, from ISO/IEC 9899
----------------------

6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to
any incomplete or object type. A pointer to any incomplete
or object type may be converted to a pointer to void and
back again; the result shall compare equal to the original
pointer.

7 A pointer to an object or incomplete type may be converted
to a pointer to a different object or incomplete type. If
the resulting pointer is not correctly aligned for the
pointed-to type, the behavior is undefined. Otherwise, when
converted back again, the result shall compare equal to the
original pointer. When a pointer to an object is converted
to a pointer to a character type, the result points to the
lowest addressed byte of the object. Successive increments
of the result, up to the size of the object, yield pointers
to the remaining bytes of the object.

8 A pointer to a function of one type may be converted to a
pointer to a function of another type and back again; the
result shall compare equal to the original pointer. If a
converted pointer is used to call a function whose type is
not compatible with the pointed-to type, the behavior is
undefined.


[The reason I used "malloc" is because of the following. The
emphasis here is on the phrase "suitably aligned."]

7.20.3 Memory management functions

1 ...
The pointer returned if the allocation succeeds is
suitably aligned so that it may be assigned to a
pointer to any type of object and then used to access
such an object or an array of such objects in the space
allocated
...
 
J

John Harrison

Dan Pop said:
You are wrong on this one. Pointers to functions cannot be converted
(either explicitly or implicitly) to pointers to void (and vice versa).
Undefined behaviour due to lack of specification in the standard.

I can't comment as to what is/isn't in the standard, however the following
compiles and runs (without any warnings) on every system I have:

#include <stdio.h>
#include <stdlib.h>

typedef int (*fooptr)(int);

int foo(int bar) {
printf("foo(%d)\n", bar);
return bar;
}

int main(void) {
fooptr f1 = NULL;
fooptr f2 = NULL;
void* v1 = NULL;

f1 = foo;

/* cast function pointer to void* */
v1 = (void*)f1;

/* cast void* to function pointer */
f2 = (fooptr)v1;

f1(1);
f2(2);
return 0;
}


In fact, the dlopen()/dlsym() dynamic loading system used on most Unix
systems wouldn't work if you couldn't convert a void* to a function
pointer...
 
D

Dan Pop

I can't comment as to what is/isn't in the standard, however the following
compiles and runs (without any warnings) on every system I have:

So what? Invoking undefined behaviour doesn't require any warning.
#include <stdio.h>
#include <stdlib.h>

typedef int (*fooptr)(int);

int foo(int bar) {
printf("foo(%d)\n", bar);
return bar;
}

int main(void) {
fooptr f1 = NULL;
fooptr f2 = NULL;
void* v1 = NULL;

f1 = foo;

/* cast function pointer to void* */
v1 = (void*)f1;

/* cast void* to function pointer */
f2 = (fooptr)v1;

f1(1);
f2(2);
return 0;
}


In fact, the dlopen()/dlsym() dynamic loading system used on most Unix
systems wouldn't work if you couldn't convert a void* to a function
pointer...

So what? This is comp.lang.c, not comp.unix.programmer. The fact that
the C standard does not define the conversion between void pointers and
function pointers doesn't mean that a Unix-specific standard cannot
define it.

Your program may not work on MS-DOS under certain memory models (16-bit
data pointers and 32-bit function pointers) and on AS/400 machines
(function pointers much wider than data pointers).

The standard provides no guarantee that void pointers are wide enough
to be able to store function pointers. In the absence of this guarantee,
your code doesn't qualify as portable.

Dan
 
C

CBFalconer

John said:
.... snip ...

I can't comment as to what is/isn't in the standard, however the
following compiles and runs (without any warnings) on every
system I have:

#include <stdio.h>
#include <stdlib.h>

typedef int (*fooptr)(int);

int foo(int bar) {
printf("foo(%d)\n", bar);
return bar;
}

int main(void) {
fooptr f1 = NULL;
fooptr f2 = NULL;
void* v1 = NULL;

f1 = foo;
/* cast function pointer to void* */
v1 = (void*)f1;
/* cast void* to function pointer */
f2 = (fooptr)v1;

f1(1);
f2(2);
return 0;
}

In fact, the dlopen()/dlsym() dynamic loading system used on most
Unix systems wouldn't work if you couldn't convert a void* to a
function pointer...

Which doesn't affect the fact that the conversions are not
guaranteed. Any such Unix functions are obviously system
specific, and don't need portability. A pointer to a function can
easily require more bits than are present in a void*.

BTW the casts are unnecessary and bad practice.
 
F

Flash Gordon

I can't comment as to what is/isn't in the standard, however the
following compiles and runs (without any warnings) on every system I
have:

Try it under DOS using the large code model and the small data model.
Some DOS compilers used to allow you to set small/large/huge
independently for code and data, an if you have a larger address range
for you code than for your data you are obviously going to need larger
pointers, and void* is defined as (in DOS terms) a data pointer.

This situation could happen again with the move from 32 to 64 bit
machines or with a later move to 128 bit machines.
#include <stdio.h>
#include <stdlib.h>

typedef int (*fooptr)(int);

int foo(int bar) {
printf("foo(%d)\n", bar);
return bar;
}

int main(void) {
fooptr f1 = NULL;
fooptr f2 = NULL;
void* v1 = NULL;

f1 = foo;

/* cast function pointer to void* */
v1 = (void*)f1;

At this point you could loose some of the address if function pointers
are larger than data pointers.
/* cast void* to function pointer */
f2 = (fooptr)v1;

f1(1);
f2(2);
return 0;
}


In fact, the dlopen()/dlsym() dynamic loading system used on most Unix
systems wouldn't work if you couldn't convert a void* to a function
pointer...

Unix is off topic here, but it is possible (based on the definition of
dlsym I would even say likely) that the POSIX standard adds a
requirement that void* be large enough to hold function pointers and
that the conversion works. Implementations are allowed to define
behaviour that the C standard leaves (or makes) undefined.
 
D

Dan Pop

In said:
BTW the casts are unnecessary and bad practice.

You forgot to engage the brain, again!

Without the casts, the program violates the constraints of 6.5.16.1p1 and
requires a diagnostic. With the casts, the program invokes undefined
behaviour and no diagnostic is required. If I remove the casts,
gcc complains (when invoked in conforming mode):

fangorn:~/tmp 284> gcc -ansi -pedantic test.c
test.c: In function `main':
test.c:19: warning: ISO C forbids assignment between function pointer and `void *'
test.c:22: warning: ISO C forbids assignment between function pointer and `void *'

With the casts in place, I get a clean compile from gcc, which is OK.

Dan
 
C

CBFalconer

Dan said:
.... snip ...

You forgot to engage the brain, again!

Without the casts, the program violates the constraints of
6.5.16.1p1 and requires a diagnostic. With the casts, the program
invokes undefined behaviour and no diagnostic is required. If I
remove the casts, gcc complains (when invoked in conforming mode):

Now you are objecting to getting diagnostics for bad code? There
is something wrong with your priorities.
 
D

Dan Pop

In said:
Now you are objecting to getting diagnostics for bad code?

It is bad code if the casts are omitted, as you advocate. It is NOT
(automatically) bad code, if the casts are in place. But I can't expect
you to understand this.
There is something wrong with your priorities.

Nope, there is something wrong with your ability of engaging the brain.

Dan
 
K

Keith Thompson

In said:
Dan said:
... snip ...

BTW the casts are unnecessary and bad practice.

You forgot to [...]
, again!

Without the casts, the program violates the constraints of
6.5.16.1p1 and requires a diagnostic. With the casts, the program
invokes undefined behaviour and no diagnostic is required. If I
remove the casts, gcc complains (when invoked in conforming mode):

Now you are objecting to getting diagnostics for bad code?

It is bad code if the casts are omitted, as you advocate. It is NOT
(automatically) bad code, if the casts are in place. But I can't expect
you to understand this.
There is something wrong with your priorities.

Nope, there is something wrong with your ability of
[...]

(Tiresome insults snipped.)

Where does the standard say that a conversion between a function
pointer and an object pointer, even with an explicit cast, is allowed?
(C99 6.3.2.3 discusses conversions between a pointer to an object or
incomplete type and a pointer to a different object or incomplete
type, and conversions between different pointer-to-function types, but
there's no mention of conversions between pointer-to-object types and
pointer-to-function types.) Or is it implicitly allowed (with
undefined behavior) because the standard doesn't disallow it?

Consider this program:

int main(void)
{
double dbl;
int *obj_ptr;
int (*func_ptr)(int);

obj_ptr = (int*)func_ptr;
func_ptr = (int (*)(int))obj_ptr;

dbl = (double)obj_ptr;
obj_ptr = (int*)dbl;

return 0;
}

The first two assignments attempt to convert between a function
pointer type and an object pointer type. The last two assignments
attempt to convert between an object pointer type and a floating-point
type.

gcc, with all warnings enabled, accepts the
function-pointer/object-pointer conversions without complaint, and
rejects the floating-point/object-pointer conversions.

Is gcc correct to accept the first two conversions and reject the last
two? If not, what should it be doing? Chapter and verse would be
appreciated.
 
G

Gordon Burditt

You are wrong on this one. Pointers to functions cannot be converted
I can't comment as to what is/isn't in the standard, however the following
compiles and runs (without any warnings) on every system I have:

Try it on a MS-DOS system in "medium" or "compact" memory model.
These models have function and data pointers of different sizes
(one 16-bits, the other 32-bits). I keep forgetting which is which.

If you convert a long pointer to a short one, you lose data.
If you convert a short pointer to a long one, chances are the
wrong information is added.

There is (or probably will be) "medium gigantic" and "super compact"
(not sure that they will use these specific names)
(32/48 bit pointers).

Gordon L. Burditt
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top