Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Do not cast pointers to functions to pointers to primitive types

Reply
Thread Tools

Do not cast pointers to functions to pointers to primitive types

 
 
Keith Thompson
Guest
Posts: n/a
 
      09-04-2012
http://www.velocityreviews.com/forums/(E-Mail Removed) (Alan Curry) writes:
> In article <(E-Mail Removed)>,
> Keith Thompson <(E-Mail Removed)> wrote:
>>James Kuyper <(E-Mail Removed)> writes:
>>> On 09/03/2012 04:21 PM, Keith Thompson wrote:
>>>> James Kuyper <(E-Mail Removed)> writes:
>>>> [...]
>>>>> 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.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Kaz Kylheku
Guest
Posts: n/a
 
      09-04-2012
On 2012-09-03, ajaybgr <(E-Mail Removed)> wrote:
> 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.
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      09-04-2012
Vincenzo Mercuri <(E-Mail Removed)> writes:
> 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.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Alan Curry
Guest
Posts: n/a
 
      09-04-2012
In article <(E-Mail Removed)>,
Keith Thompson <(E-Mail Removed)> wrote:
>(E-Mail Removed) (Alan Curry) writes:
>>
>> 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.

--
Alan Curry
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      09-04-2012
(E-Mail Removed) (Alan Curry) writes:
> In article <(E-Mail Removed)>,
> Keith Thompson <(E-Mail Removed)> wrote:
>>(E-Mail Removed) (Alan Curry) writes:
>>>
>>> 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?

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Alan Curry
Guest
Posts: n/a
 
      09-04-2012
In article <(E-Mail Removed)>,
Keith Thompson <(E-Mail Removed)> wrote:
>
>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.

--
Alan Curry
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      09-04-2012
On 09/04/2012 04:27 PM, Alan Curry wrote:
> In article <(E-Mail Removed)>,
> Keith Thompson <(E-Mail Removed)> wrote:
>>
>> 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.


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.

 
Reply With Quote
 
Barry Schwarz
Guest
Posts: n/a
 
      09-04-2012
On Tue, 4 Sep 2012 20:27:14 +0000 (UTC), (E-Mail Removed) (Alan
Curry) wrote:

>In article <(E-Mail Removed)>,
>Keith Thompson <(E-Mail Removed)> wrote:
>>
>>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.


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.

--
Remove del for email
 
Reply With Quote
 
Philip Lantz
Guest
Posts: n/a
 
      09-07-2012
Scott Fluhrer wrote:
> 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;
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
destroy primitive/object types but memory is not freed george972@mailinator.com C Programming 5 05-25-2009 10:44 PM
Default primitive values from primitive Class<?> object. Daniel Pitts Java 7 10-23-2008 04:30 PM
Primitive vs. non-primitive l-value richardclay09@yahoo.co.uk C++ 7 05-09-2005 02:52 PM
error C2440: 'return' : cannot convert from 'const char *' to 'const unsigned short *' Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast Abhijit Bhadra C++ 2 12-01-2004 04:43 PM
use delete to destroy primitive/object types but memory is not freed jimjim C Programming 28 04-13-2004 11:34 PM



Advertisments