473,394 Members | 1,787 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Is this valid C statement?

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
Nov 14 '05 #1
24 1761
s.subbarayan <s_**********@rediffmail.com> scribbled the following:
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.)

--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"To err is human. To really louse things up takes a computer."
- Anon
Nov 14 '05 #2
"s.subbarayan" <s_**********@rediffmail.com> wrote in message
news:c3**************************@posting.google.c om...
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.
Nov 14 '05 #3
Joona I Palaste <pa*****@cc.helsinki.fi> scribbled the following:
s.subbarayan <s_**********@rediffmail.com> scribbled the following:
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 (pa*****@cc.helsinki.fi) ------------- 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
Nov 14 '05 #4
Joona I Palaste <pa*****@cc.helsinki.fi> wrote:
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.

--
Stan Tobias
sed 's/[A-Z]//g' to email
Nov 14 '05 #5
In <cj**********@oravannahka.helsinki.fi> Joona I Palaste <pa*****@cc.helsinki.fi> writes:
s.subbarayan <s_**********@rediffmail.com> scribbled the following:
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
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #6
Dan Pop <Da*****@cern.ch> scribbled the following:
In <cj**********@oravannahka.helsinki.fi> Joona I Palaste <pa*****@cc.helsinki.fi> writes:
s.subbarayan <s_**********@rediffmail.com> scribbled the following:
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 (pa*****@cc.helsinki.fi) ------------- 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
Nov 14 '05 #7
Joona I Palaste wrote:

Dan Pop <Da*****@cern.ch> scribbled the following:

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.


"anything" could read to include incomplete types too.

--
pete
Nov 14 '05 #8
kal
Joona I Palaste <pa*****@cc.helsinki.fi> wrote in message news:<cj**********@oravannahka.helsinki.fi>...
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);
Nov 14 '05 #9
kal <k_*****@yahoo.com> scribbled the following:
Joona I Palaste <pa*****@cc.helsinki.fi> wrote in message news:<cj**********@oravannahka.helsinki.fi>...
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);


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

--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
Nov 14 '05 #10
kal
Joona I Palaste <pa*****@cc.helsinki.fi> wrote in message news:<cj**********@oravannahka.helsinki.fi>...
kal <k_*****@yahoo.com> scribbled the following:
Joona I Palaste <pa*****@cc.helsinki.fi> wrote in message news:<cj**********@oravannahka.helsinki.fi>...
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);


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
...
Nov 14 '05 #11

"Dan Pop" <Da*****@cern.ch> wrote in message
news:cj**********@sunnews.cern.ch...
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.


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...


Nov 14 '05 #12
John Harrison wrote:
"Dan Pop" <Da*****@cern.ch> wrote in message

.... snip ...

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...


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.

--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 14 '05 #13
In <41********@hawk.winshop.com.au> "John Harrison" <jo**@hiame.com> writes:

"Dan Pop" <Da*****@cern.ch> wrote in message
news:cj**********@sunnews.cern.ch...
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.


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
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #14
In <41***************@yahoo.com> CBFalconer <cb********@yahoo.com> writes:
John Harrison wrote:

#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;
}

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
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #15
On Thu, 30 Sep 2004 21:58:50 +1000
"John Harrison" <jo**@hiame.com> wrote:

"Dan Pop" <Da*****@cern.ch> wrote in message
news:cj**********@sunnews.cern.ch...
You are right on this one. A pointer to anything can be assignedinto 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.


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.
--
Flash Gordon
Sometimes I think shooting would be far too good for some people.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #16
Dan Pop wrote:
CBFalconer <cb********@yahoo.com> writes:

.... snip ...

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):


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

--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Nov 14 '05 #17
In <41***************@yahoo.com> CBFalconer <cb********@yahoo.com> writes:
Dan Pop wrote:
CBFalconer <cb********@yahoo.com> writes:
... snip ...

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):


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
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #18
Da*****@cern.ch (Dan Pop) writes:
In <41***************@yahoo.com> CBFalconer <cb********@yahoo.com> writes:
Dan Pop wrote:
CBFalconer <cb********@yahoo.com> writes:

... 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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #19
>> 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:


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
Nov 14 '05 #20
boa
Keith Thompson wrote:

[snip]
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?


Doesn't 6.3.2.3#5 and #6 allow us to convert "Any pointer type" to and
from an integer? Ignoring the obvious implementation-defined issues, it
should therefore be OK to convert pfunc -> int -> pdata, shouldn't it?

boa
[snip]
Nov 14 '05 #21
Da*****@cern.ch (Dan Pop) writes:
In <ln************@nuthaus.mib.org> Keith Thompson <ks***@mib.org> writes:
Where does the standard say that a conversion between a function
pointer and an object pointer, even with an explicit cast, is allowed?
Nowhere. I have explicitly stated, upthread, that this is a case of
undefined behaviour (reread the thread if your memory is leaky). So what
*exactly* is your point?


So if it's a case of undefined behavior, then it's "allowed", in the
sense in which I was using the word. My meaning was clear from the
last sentence of that paragraph that you snipped:

] Or is it implicitly allowed (with undefined behavior) because the
] standard doesn't disallow it?
If you don't get my point, here it is: this is one case when invoking
undefined behaviour is not *necessarily* a bad thing, if you know what
you're doing.
Yes, I understand that.
And if you still don't get it, please point out a way of using dlsym()
without invoking undefined behaviour by converting its return value
to a pointer to function. The fact that dlsym() is not a standard
library function is immaterial: the <dlfcn.h> interface is covered by
Unix standards and there are Unix programs needing it.


Yes, I understand that.

Here's the sample program I posted previously (with added comments):

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

obj_ptr = (int*)func_ptr; /* (1) */
func_ptr = (int (*)(int))obj_ptr; /* (2) */

dbl = (double)obj_ptr; /* (3) */
obj_ptr = (int*)dbl; /* (4) */

return 0;
}

I believe that each of the 4 marked conversions either requires a
diagnostic or invokes undefined behavior. My suspicion is that (1)
and (2) invoke undefined behavior and do not require diagnostics, and
that (3) and (4) do require diagnostics. I haven't been able to
confirm this in the standard (though it's consistent with gcc's
behavior). C99 6.3.2.3 specifies what pointer conversions are
allowed; it doesn't mention either conversions between
pointer-to-function types and pointer-to-object types, or conversions
between pointer-to-object types and floating-point types. That seems
to me to imply that either all four conversions above require a
diagnostic, or that none of them do but all four invoke undefined
behavior. (This contradicts my suspicion, and implies that gcc is
misbehaving.)

Dan, I know you've asserted that converting between a function pointer
and an object pointer invokes undefined behavior. I don't necessarily
disagree; I'm just looking for a definitive statement, one way or the
other, from the standard. If you don't know the answer, or if you
still don't understand what I'm asking, please feel free to sit back
and let someone else answer my questions.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #22
In <ln************@nuthaus.mib.org> Keith Thompson <ks***@mib.org> writes:
Da*****@cern.ch (Dan Pop) writes:
In <ln************@nuthaus.mib.org> Keith Thompson <ks***@mib.org> writes:
Where does the standard say that a conversion between a function
pointer and an object pointer, even with an explicit cast, is allowed?
Nowhere. I have explicitly stated, upthread, that this is a case of
undefined behaviour (reread the thread if your memory is leaky). So what
*exactly* is your point?


So if it's a case of undefined behavior, then it's "allowed", in the
sense in which I was using the word.


Which is not the sense usually accepted in this newsgroup.
My meaning was clear from the
last sentence of that paragraph that you snipped:

] Or is it implicitly allowed (with undefined behavior) because the
] standard doesn't disallow it?
"Implicitly allowed (with undefined behavior)" is an oxymoron in c.l.c.
Note that NO compiler is required by the standard to accept this
programming construct.

A better choice of words from your part would have avoided this
misunderstanding.
Here's the sample program I posted previously (with added comments):

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

obj_ptr = (int*)func_ptr; /* (1) */
func_ptr = (int (*)(int))obj_ptr; /* (2) */

dbl = (double)obj_ptr; /* (3) */
obj_ptr = (int*)dbl; /* (4) */

return 0;
}

I believe that each of the 4 marked conversions either requires a
diagnostic or invokes undefined behavior. My suspicion is that (1)
and (2) invoke undefined behavior and do not require diagnostics, and
that (3) and (4) do require diagnostics. I haven't been able to
confirm this in the standard (though it's consistent with gcc's
behavior). C99 6.3.2.3 specifies what pointer conversions are
allowed; it doesn't mention either conversions between
pointer-to-function types and pointer-to-object types, or conversions
between pointer-to-object types and floating-point types. That seems
to me to imply that either all four conversions above require a
diagnostic, or that none of them do but all four invoke undefined
behavior.
All four of them invoke undefined behaviour, by lack of definition of
behaviour:

2 If a ``shall'' or ``shall not'' requirement that appears outside
of a constraint is violated, the behavior is undefined. Undefined
behavior is otherwise indicated in this International Standard
by the words ``undefined behavior'' or by the omission of any
^^^^^^^^^^^^^^^^^^^^^^^^^
explicit definition of behavior. There is no difference in
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
emphasis among these three; they all describe ``behavior that
is undefined''.
(This contradicts my suspicion, and implies that gcc is misbehaving.) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Huh?!? If all of them invoke undefined behaviour, there is NO way gcc
could misbehave in handling them (regardless of what it actually does or
doesn't).

gcc associates meaningful (and possibly useful) semantics to the first
two cases, which is trivial on any von Neumann architecture and even
on Harvard architectures with data and code spaces of the same size.
So, it *silently* handles them (there is nothing requiring a diagnostic
for them in the standard).

OTOH, gcc doesn't assign any meaningful semantics to the last two cases.
Although not required to, he chooses to let the programmer know that,
from its point of view, they are meaningless, by issuing a diagnostic.

We're dealing here with two different reasons for the language
specification opting for undefined behaviour:

1. Some semantics could be specified, but it wouldn't make sense on all
C implementations. This is the case for conversions between data
pointers (pointers to incomplete types are still data pointers)
and function pointers. Compare your vanilla von Neuman architecture
with the AS/400 (128-bit data pointers and 768-bit function pointers).

2. No meaningful semantics could be defined for the operation. This is
the case for conversions betwee floating point values and pointer
values.
Dan, I know you've asserted that converting between a function pointer
and an object pointer invokes undefined behavior. I don't necessarily
disagree; I'm just looking for a definitive statement, one way or the
other, from the standard.


If the above is not definitive enough for you, you know where to find
comp.std.c. I don't claim to possess the ultimate interpretation of *any*
paragraph of the C standard...

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #23
Keith Thompson <ks***@mib.org> writes:
[...]
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?

[...]

What I was really looking for was an explicit statement about which
conversions are legal and which are not, particularly those involving
pointer types. (By "legal", I mean not requiring a diagnostic.)

C99 6.3.2.3 enumerates a number of kinds of conversions that are
allowed (it uses the phrase "may be converted"). (6.3.1 discusses
arithmetic operands.) Some potential conversions are not enumerated,
for example conversions between pointer types and floating-point
types; such conversions are unlikely to make much sense on most
implementations, but it seemed odd to me that they aren't mentioned.
I was also wondering about even less sensible conversions, such as
between pointers and structs.

The piece of the puzzle that I was missing was 6.5.4, "Cast
operators":

Unless the type name specifies a void type, the type name shall
specify qualified or unqualified scalar type and the operand shall
have scalar type.

Conversions that involve pointers, other than where permitted by
the constraints of 6.5.16.1, shall be specified by means of an
explicit cast.

I think this means that conversion between a pointer type and a
floating-point type does not require a diagnostic (it doesn't violate
any constraint), but it invokes undefined behavior, since the standard
doesn't define what the behavior is. On the other hand, conversion
between a pointer type and a struct type is illegal; an explicit cast
is not allowed because one of the types is not scalar, and there's no
way to do the conversion implicitly.

I've tried the following program with several C compilers:

int main(void)
{
double dbl = 0.0;
int *ptr;
ptr = (int*)dbl;
return 0;
}

The assignment, if I'm correct, is legal but invokes undefined
behavior. Every compiler I've tried prints a diagnostic and rejects
the program:

error: cannot convert to a pointer type

invalid cast expression

The indicated type conversion is invalid.

"double" cannot be converted to "int*".

In this statement, "dbl" is of type "double", and cannot be
converted to "pointer to int"

I suppose printing a diagnostic and rejecting the program is a valid
consequence of undefined behavior, but it's not something that most
compilers generally do. Most C compilers typically print at most a
warning for undefined behavior, but don't reject the program.

The behavior of any one compiler, or even of any five compilers, is
not of course definitive in interpreting the standard, but it does
appear that the implementers of those compilers thought that
converting a floating-point value to a pointer type is illegal.

Is there a statement in the C standard that a conversion from a
floating-point type to a pointer type is a constraint violation?

I acknowledge that this isn't a particularly practical question unless
you're writing a compiler; it wouldn't occur to most of us to try to
convert a floating-point value to a pointer type in the first place.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #24
In <ln************@nuthaus.mib.org> Keith Thompson <ks***@mib.org> writes:
The piece of the puzzle that I was missing was 6.5.4, "Cast
operators":

Unless the type name specifies a void type, the type name shall
specify qualified or unqualified scalar type and the operand shall
have scalar type.

Conversions that involve pointers, other than where permitted by
the constraints of 6.5.16.1, shall be specified by means of an
explicit cast.

I think this means that conversion between a pointer type and a
floating-point type does not require a diagnostic (it doesn't violate
any constraint), but it invokes undefined behavior, since the standard
doesn't define what the behavior is.
Correct.
I've tried the following program with several C compilers:

int main(void)
{
double dbl = 0.0;
int *ptr;
ptr = (int*)dbl;
return 0;
}

The assignment, if I'm correct, is legal but invokes undefined
behavior.
The undefined behaviour is invoked *before* the assignment, by the time
the cast operator is evaluated. If the implementation happens to support
the conversion, the assignment itself *may* invoke undefined behaviour,
too, depending on the actual result of the conversion. But, as far as the
language specification is concerned, this is irrelevant: only the first
instance of undefined behaviour counts.
Every compiler I've tried prints a diagnostic and rejects
the program:

error: cannot convert to a pointer type

invalid cast expression

The indicated type conversion is invalid.

"double" cannot be converted to "int*".

In this statement, "dbl" is of type "double", and cannot be
converted to "pointer to int"

I suppose printing a diagnostic and rejecting the program is a valid
consequence of undefined behavior,
It's explicitly listed in the standard:

2 NOTE Possible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of
a diagnostic message), to terminating a translation or execution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(with the issuance of a diagnostic message).
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
but it's not something that most
compilers generally do. Most C compilers typically print at most a
warning for undefined behavior, but don't reject the program.
There are two kinds of undefined behaviour at translation time:

1. The ones the compiler can detect. In most such cases, compilers assign
semantics to them, so they have no reason to reject the program. They
trust the programmer to be happy with the semantics provided by the
compiler. They may diagnose them, but typically only if the user
invokes the compiler in "picky" mode.

2. The ones the compiler cannot (or doesn't even try to) detect.
Obviously, no special action can be expected from the compiler.

Your example is a rare exception from the first category: the compiler
can detect it, but it doesn't assign any special semantics to it. What
should it do?
Is there a statement in the C standard that a conversion from a
floating-point type to a pointer type is a constraint violation?


Not that I know of. Why should there be one?

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #25

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Michael Hill | last post by:
Is this a valid sql statement: SELECT case field1 when 'first' then 1 when 'second' then 1 else null end FROM mytable
1
by: Maria | last post by:
Hello we got a script automatically generated to populate a table that belongs to a partition table, then while executing we get this error message: "DB21034E The command was processed as an...
9
by: Alberto | last post by:
Eh unfortunately Google groups does not provide any longer a way to reply to the group for older posts (though the one I am referring to is not older than one month), and I happen to come back to...
2
by: chrisshearier | last post by:
The below statement is causing System.InvalidCastException: Specified cast is not valid. Can anyone see what is going wrong with this and help me out. string statement =...
4
by: Jatinder | last post by:
Hi, I am trying to grant connect privilege to a user present on my O.S. (Windows) using following statement. GRANT CONNECT ON DATABASE TO user "user1" now when I execute this statemnt from...
5
by: nospam | last post by:
Hi all. I have encountered a "Cross-thread operation not valid" error in a test program I created and although I have came up with a solution I don't like the performance of the program. I...
0
by: PeterA | last post by:
I have a Windows PC connecting to ISeries with ODBC. The windows PC uses various SQL statements to connect to DB2 and download/upload data. Data downloads/uploads appear to be OK and I can't see...
2
by: anon.asdf | last post by:
Hello! 1) =============================== When trying to define an array of std::string ... func( (std::string ) { std::string("ab"), std::string("cd"), std::string("ef") } , 3 ); ...
14
by: paresh | last post by:
Is this the valid C statement. int a,b,c; c = 5; <<< a = b = c; Can anyone throw the light on this. -Paresh
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.