Do not cast pointers to functions to pointers to primitive types

A

ajaybgr

Not sure if this is the right place or OT.
One of the Parasoft coding guidelines (which I am using for current project) is
"Do not cast pointers to functions to pointers to primitive types [CODSTA-09-3]"

EXAMPLE(from parasoft document):
void Foo(char *ptrC)
{
*ptrC = 0;
return;
}

void f()
{
void *ptrV = 0;
void (*funPtr) (char*) = 0;
funPtr = &Foo;
ptrV = (void*)funPtr; // Violation of the rule and raise error
return;
}

I can see why it is a bad idea not to write code this way.
But can any one explain where this kind of code is useful?
(imo, to be a guideline it must have been used/misused a lot)
Where casting a function pointer to primitive type makes sense?
Sorry if this is too silly, my mind seems to have hit a wall today.

Regards
Ajay
 
I

Ian Collins

Not sure if this is the right place or OT.
One of the Parasoft coding guidelines (which I am using for current project) is
"Do not cast pointers to functions to pointers to primitive types [CODSTA-09-3]"

EXAMPLE(from parasoft document):
void Foo(char *ptrC)
{
*ptrC = 0;
return;
}

void f()
{
void *ptrV = 0;
void (*funPtr) (char*) = 0;
funPtr =&Foo;
ptrV = (void*)funPtr; // Violation of the rule and raise error
return;
}

I can see why it is a bad idea not to write code this way.
But can any one explain where this kind of code is useful?

In a bad dream...
(imo, to be a guideline it must have been used/misused a lot)
Where casting a function pointer to primitive type makes sense?

An awful lot of bad C code has been has been hacked together in the past
30+ years!
 
N

Nick Keighley

Not sure if this is the right place or OT.
One of the Parasoft coding guidelines (which I am using for current project) is
"Do not cast pointers to functions to pointers to primitive types [CODSTA-09-3]"

EXAMPLE(from parasoft document):
void Foo(char *ptrC)
{
    *ptrC = 0;
    return;

}

void f()
{
    void *ptrV = 0;
    void (*funPtr) (char*) = 0;
    funPtr = &Foo;
    ptrV = (void*)funPtr; // Violation of the rule and raise error
    return;

}

I can see why it is a bad idea not to write code this way.
But can any one explain where this kind of code is useful?
(imo, to be a guideline it must have been used/misused a lot)
Where casting a function pointer to primitive type makes sense?
Sorry if this is too silly, my mind seems to have hit a wall today.

it probably arises from the misconception that "void* is a pointer to
anything" since on most architectures object pointers and functions
pointers are "just addreses" you can get away with it a lot of the
time. Yes it is a bad idea.
 
B

Ben Bacarisse

ajaybgr said:
Not sure if this is the right place or OT. One of the Parasoft coding
guidelines (which I am using for current project) is "Do not cast
pointers to functions to pointers to primitive types [CODSTA-09-3]"

EXAMPLE(from parasoft document):
void Foo(char *ptrC)
{
*ptrC = 0;
return;
}

void f()
{
void *ptrV = 0;
void (*funPtr) (char*) = 0;
funPtr = &Foo;
ptrV = (void*)funPtr; // Violation of the rule and raise error
return;
}

I can see why it is a bad idea not to write code this way.
But can any one explain where this kind of code is useful?
(imo, to be a guideline it must have been used/misused a lot)
Where casting a function pointer to primitive type makes sense?

Like others, I can't really answer your question except to add that
these sorts of conversion are undefined according to the definition of
C. It's possible, then, that the rule is in your coding guidelines, not
because it's so tempting, but simply because it's a no-so-well-known
rule of the language.
 
J

James Kuyper

Not sure if this is the right place or OT.
One of the Parasoft coding guidelines (which I am using for current project) is
"Do not cast pointers to functions to pointers to primitive types [CODSTA-09-3]"

EXAMPLE(from parasoft document):
void Foo(char *ptrC)
{
*ptrC = 0;
return;
}

void f()
{
void *ptrV = 0;
void (*funPtr) (char*) = 0;
funPtr = &Foo;
ptrV = (void*)funPtr; // Violation of the rule and raise error
return;
}

I can see why it is a bad idea not to write code this way.
But can any one explain where this kind of code is useful?
(imo, to be a guideline it must have been used/misused a lot)
Where casting a function pointer to primitive type makes sense?
Sorry if this is too silly, my mind seems to have hit a wall today.

There are real platforms, in common use, where the behavior of such
code, while not defined by the C standard, is defined by some other
standard, and there's a fair amount of code written for those platforms
which actually relies upon that assumption. This produces the
unjustified but understandable belief that the technique will work
everywhere.

Example: the dlsym() function is specified by the X-open standard to
take a void* argument which can be either a pointer to an object or a
pointer to a function. The Rationale for that function notes;
 
K

Keith Thompson

James Kuyper said:
Example: the dlsym() function is specified by the X-open standard to
take a void* argument which can be either a pointer to an object or a
pointer to a function. The Rationale for that function notes;
[...]
Note that compilers conforming to the ISO C standard are required to
generate a warning if a conversion from a void * pointer to a
function pointer is attempted.
[...]

I don't believe that's correct. The behavior of converting a void*
pointer to a function pointer is not defined, but as far as I can tell
it doesn't violate any constraint.

A concrete example:

int obj;
void *vp = &obj;
void (*fp)(void) = (void (*)(void))vp;

The constraints on a cast operator are described in N1570 6.5.4.
The cast in the above code doesn't violate any of them. (Perhaps
there *should* be such a constraint.)

Or am I missing something?
 
J

James Kuyper

James Kuyper said:
Example: the dlsym() function is specified by the X-open standard to
take a void* argument which can be either a pointer to an object or a
pointer to a function. The Rationale for that function notes;
[...]
Note that compilers conforming to the ISO C standard are required to
generate a warning if a conversion from a void * pointer to a
function pointer is attempted.
[...]

I don't believe that's correct. The behavior of converting a void*
pointer to a function pointer is not defined, but as far as I can tell
it doesn't violate any constraint.

A concrete example:

int obj;
void *vp = &obj;
void (*fp)(void) = (void (*)(void))vp;

The constraints on a cast operator are described in N1570 6.5.4.
The cast in the above code doesn't violate any of them. (Perhaps
there *should* be such a constraint.)

Or am I missing something?

It's possible that they're referring to implicit conversion, rather than
one using a cast.
 
K

Keith Thompson

James Kuyper said:
James Kuyper said:
Example: the dlsym() function is specified by the X-open standard to
take a void* argument which can be either a pointer to an object or a
pointer to a function. The Rationale for that function notes;
[...]
Note that compilers conforming to the ISO C standard are required to
generate a warning if a conversion from a void * pointer to a
function pointer is attempted.
[...]

I don't believe that's correct. The behavior of converting a void*
pointer to a function pointer is not defined, but as far as I can tell
it doesn't violate any constraint.
[...]

It's possible that they're referring to implicit conversion, rather than
one using a cast.

It's possible, but if so they phrased it poorly.

Note that gcc also appears to get this wrong (assuming my interpretation
is correct). With "-std=c11 -pedantic", gcc 4.7 complains:

warning: ISO C forbids conversion of object pointer to function pointer type [-pedantic]
 
A

Alan Curry

James Kuyper said:
[...]
Example: the dlsym() function is specified by the X-open standard to
take a void* argument which can be either a pointer to an object or a
pointer to a function. The Rationale for that function notes;

[...]
Note that compilers conforming to the ISO C standard are required to
generate a warning if a conversion from a void * pointer to a
function pointer is attempted.
[...]

I don't believe that's correct. The behavior of converting a void*
pointer to a function pointer is not defined, but as far as I can tell
it doesn't violate any constraint.
[...]

It's possible that they're referring to implicit conversion, rather than
one using a cast.

It's possible, but if so they phrased it poorly.

Any idiot should be able to read that and know without being told that using
a cast will get rid of the warning. Casts do that. It's obvious.
 
V

Vincenzo Mercuri

On 03/09/2012 22:21, Keith Thompson wrote:
[..]
A concrete example:

int obj;
void *vp = &obj;
void (*fp)(void) = (void (*)(void))vp;

The constraints on a cast operator are described in N1570 6.5.4.
The cast in the above code doesn't violate any of them. (Perhaps
there*should* be such a constraint.)

Or am I missing something?

My understanding is that there is not such a constraint to allow
such casts as a "common extension", N1570 J.5.7:

A pointer to an object or to void may be cast to a pointer
to a function, allowing data to be invoked as a function (6.5.4).

A pointer to a function may be cast to a pointer to an object or to
void, allowing a function to be inspected or modified (for example,
by a debugger) (6.5.4).

If that cast violated a constraint any implementation with such
extension would be nonconforming. I only see a warning with gcc
however when `-pedantic' is enabled.
 
K

Keith Thompson

James Kuyper said:
On 09/03/2012 04:21 PM, Keith Thompson wrote:
[...]
Example: the dlsym() function is specified by the X-open standard to
take a void* argument which can be either a pointer to an object or a
pointer to a function. The Rationale for that function notes;

[...]
Note that compilers conforming to the ISO C standard are required to
generate a warning if a conversion from a void * pointer to a
function pointer is attempted.
[...]

I don't believe that's correct. The behavior of converting a void*
pointer to a function pointer is not defined, but as far as I can tell
it doesn't violate any constraint. [...]

It's possible that they're referring to implicit conversion, rather than
one using a cast.

It's possible, but if so they phrased it poorly.

Any idiot should be able to read that and know without being told that using
a cast will get rid of the warning. Casts do that. It's obvious.

Were you aware that we're talking about conversion from void* to
a function pointer, a conversion whose behavior is not defined by
the standard, whether it's done by a cast or not? This is quite
distinct from other pointer-to-pointer conversions, which in most
cases merely yield an implementation-defined result.

I posted a code snippet upthread. Here's a small complete program:

int main(void) {
int obj;
void *vp = &obj;
void (*fp)(void) = (void (*)(void))vp; /* line 4 */
return 0;
}

When I compile this with gcc 4.7, with "-pedantic" and any of
"-std={c90,c99,c11}", I get the following warning:

c.c:4:24: warning: ISO C forbids conversion of object pointer to function pointer type [-pedantic]

I get the same warning with or without the (void (*)(void)) cast.
(Without the cast, it's definitely a constraint violation.)

You might want to reconsider your "Any idiot" statement.
 
K

Kaz Kylheku

Not sure if this is the right place or OT.
One of the Parasoft coding guidelines (which I am using for current project) is
"Do not cast pointers to functions to pointers to primitive types [CODSTA-09-3]"

[ snip ]
I can see why it is a bad idea not to write code this way.
But can any one explain where this kind of code is useful?

Such code is found in the implementation of shared libraries.

For instance, the dlsym function on POSIX returns void *,
and this function is used whether you're looking up a function or some other
kind of symbol.

There is nothing wrong with doing this, except that it's not "maximally
portable".

For instance, here is one potential problem: what if function pointers are 48
bits wide and object pointers 32 bits wide.

If you're sure that portability isn't an issue, then it may be the best way to
solve the kind of problem that it solves, because doing it portably (e.g. with
unions to store two kinds of pointers in the same space) may add some clutter
to the program.
(imo, to be a guideline it must have been used/misused a lot)
Where casting a function pointer to primitive type makes sense?

Where you're going to cast it back to a function pointer type later.

Say you have a linked list which stores "void *" items and you want to
put function pointers in it.
 
K

Keith Thompson

Vincenzo Mercuri said:
On 03/09/2012 22:21, Keith Thompson wrote:
[..]
A concrete example:

int obj;
void *vp = &obj;
void (*fp)(void) = (void (*)(void))vp;

The constraints on a cast operator are described in N1570 6.5.4.
The cast in the above code doesn't violate any of them. (Perhaps
there*should* be such a constraint.)

Or am I missing something?

My understanding is that there is not such a constraint to allow
such casts as a "common extension", N1570 J.5.7:

A pointer to an object or to void may be cast to a pointer
to a function, allowing data to be invoked as a function (6.5.4).

A pointer to a function may be cast to a pointer to an object or to
void, allowing a function to be inspected or modified (for example,
by a debugger) (6.5.4).

If that cast violated a constraint any implementation with such
extension would be nonconforming. I only see a warning with gcc
however when `-pedantic' is enabled.

It's not necessary to omit a constraint to allow an extension like
this. Many extensions give meaning to code that would otherwise
violate a constraint or syntax rule. The compiler has to issue
a diagnostic (which can be a non-fatal warning) if it's invoked
in conforming mode; once it's issued the warning, it's free to do
whatever the extension specifies. And/or the compiler can have a
non-conforming mode that implements the extension without complaint.

An example: gcc permits arithmetic on void* pointers as an extension.
Any such arithmetic is a constraint violation.

Looking through the list of common extensions in J.5, some of
them can break strictly conforming programs, which violates 4p6.
Predefined macro names not starting with an underscore are one
example.
 
A

Alan Curry

[email protected] (Alan Curry) said:
Any idiot should be able to read that and know without being told that using
a cast will get rid of the warning. Casts do that. It's obvious.
[...]

I posted a code snippet upthread. Here's a small complete program:

int main(void) {
int obj;
void *vp = &obj;
void (*fp)(void) = (void (*)(void))vp; /* line 4 */
return 0;
}

When I compile this with gcc 4.7, with "-pedantic" and any of
"-std={c90,c99,c11}", I get the following warning:

c.c:4:24: warning: ISO C forbids conversion of object pointer to
function pointer type [-pedantic]

I get the same warning with or without the (void (*)(void)) cast.
(Without the cast, it's definitely a constraint violation.)

You might want to reconsider your "Any idiot" statement.

I reassert "idiot" in the direction of gcc then. Casts should be silent.
 
K

Keith Thompson

[email protected] (Alan Curry) said:
Any idiot should be able to read that and know without being told that using
a cast will get rid of the warning. Casts do that. It's obvious.
[...]

I posted a code snippet upthread. Here's a small complete program:

int main(void) {
int obj;
void *vp = &obj;
void (*fp)(void) = (void (*)(void))vp; /* line 4 */
return 0;
}

When I compile this with gcc 4.7, with "-pedantic" and any of
"-std={c90,c99,c11}", I get the following warning:

c.c:4:24: warning: ISO C forbids conversion of object pointer to
function pointer type [-pedantic]

I get the same warning with or without the (void (*)(void)) cast.
(Without the cast, it's definitely a constraint violation.)

You might want to reconsider your "Any idiot" statement.

I reassert "idiot" in the direction of gcc then. Casts should be silent.

So you don't want to distinguish between casts whose behavior
is well defined, those whose behavior is implementation-defined,
and those whose behavior is completely undefined?

I can understand that opinion, but it hardly seems reasonable to
call those who disagrees with it idiots.

Casts are commonly interpreted to mean "Shut up, compiler, I know
what I'm doing"-- but the standard doesn't say or imply that.

How do you feel about casts applied to struct types, which are a
constraint violation?
 
A

Alan Curry

So you don't want to distinguish between casts whose behavior
is well defined, those whose behavior is implementation-defined,
and those whose behavior is completely undefined?

I can understand that opinion, but it hardly seems reasonable to
call those who disagrees with it idiots.

Casts are commonly interpreted to mean "Shut up, compiler, I know
what I'm doing"-- but the standard doesn't say or imply that.

How do you feel about casts applied to struct types, which are a
constraint violation?

Those are errors, not warnings. You can't cast away an error.

Failure to distinguish errors and warnings is a problem that only The
Standard has. In the real world everybody knows they're different.
 
J

James Kuyper

Those are errors, not warnings. You can't cast away an error.

Failure to distinguish errors and warnings is a problem that only The
Standard has. In the real world everybody knows they're different.

The standard cannot distinguish between error messages and warning
messages, because whether or not something constitutes an error is
highly dependent on factors outside the scope of the standard. The code
in question has undefined behavior, the worst thing that the standard
can say about any code construct. However, the X/Open standard does
define the behavior (a fact which is outside the scope of the C
standard). A programmer who decides to write code which relies upon that
definition, believing that it will only ever need to be run on systems
that conform to the X/Open standard (something else that is also outside
the scope of the C standard) is NOT making an error (unless that belief
is incorrect).

The standard leaves the distinction between errors and warnings up to
the implementations. Were you rewriting the C standard to remove that
freedom, how would you make that distinction in such a way as to apply
to cases like this? It seems to me that a mind-reading compiler with the
capacity to make better judgements than the developer about the
reasonability of such beliefs is needed, in order to make that distinction.
 
B

Barry Schwarz

Those are errors, not warnings. You can't cast away an error.

Of course you can. Consider

int * x = NULL;
float *y = x;

This is an error. Adding the appropriate cast to the last expression
eliminates the error.
Failure to distinguish errors and warnings is a problem that only The
Standard has. In the real world everybody knows they're different.

Yes, but not everyone agrees on which side of the line a particular
situation falls, or even if the situation always falls on the same
side of the line.
 
P

Philip Lantz

Scott said:
Actually, if you are in such a circumstance (where you need to store a
function pointer, and some infrastructure only gives you a void * to store
it in), there is a totally portable way to handle it. Instead of attempting
to store the function pointer into the void * type, store a pointer to a
pointer to the function instead, For example:

Your suggestion is workable, but your example doesn't work.
typedef void (*function)(int, double, char *);

void my_function(int a, double b, char *c);
function *p_my_function = &my_function; /* p_my_function is a pointer to a
'primitive type', specifically, a function pointer type */

The above initialization is still attempting to store a pointer to a
function in a pointer to a pointer to a function. You haven't defined an
object for p_my_function to point to.
struct linked_list {
void *data;
}

/* Functions which uses the linked_list type */
struct linked_list *p;
p->data = p_my_function; /* Completely portable, because we can assign a
data pointer to a void * type */

...

function *func = p->data; /* Again, completely portable; the pointer func
is a data pointer */
(*func)( 7, 3.14159, "Hi ma!" );


I think what you meant is:

function p_my_function = &my_function;
function *pp_my_function = &p_my_function;
....
p->data = pp_my_function;

or, more simply:

function p_my_function = &my_function;
....
p->data = &p_my_function;
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top