LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-24-2008, 11:43 AM   #1
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148
Blog Entries: 1

Rep: Reputation: 48
C++ pointer cast from object to function


Okay, so I'm building a couple of C++ source files with '-Wall -ansi -pendantic', and I'm only getting a single warning (I plan to use this code as a demonstration/make-me-look-good-for-interviews, so I really want it to be perfect).

The warning I get is that "ANSI C++ forbids casting between pointer-to-object and pointer-to-function". I am casting from a an object- to function-pointer intentionally. The referenced line is pulling a symbol from a dynamically loaded module via dylsym() and casting it to the appropriate function type.

My question is, is there some correct way to make this error go away? I'd prefer not to use funky #pragma's or other non-portability if I can. Is there some "correct" way to do this cast? Or will I just have to live with the one warning?
 
Old 08-24-2008, 12:11 PM   #2
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
You can cast a void* to either an object or a function, so you need to make the cast at the point of dlsym while it's still a void*.
ta0kira
 
Old 08-24-2008, 12:16 PM   #3
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Hrmm, it is a void pointer that is being cast from. The following is the relevant snippet.
Code:
    typedef Applet* (*applet_creator)(Configuration&);
    void* ptr;
    ids[name].second->get_symbol("create_applet", ptr);
    //Create the applet
    applets.push_back(((applet_creator)ptr)(*(new Configuration(*backings[id].first, id))));
Note that the typedef was moved into the segment to present just one clip, it originally appeared at the top of the file. "ids[name].second" refers to a Glib::Module, a wrapper around dlopen/dlsym/dlclose. It's putting the symbol into its second argument.

I had thought that anything went if you passed through a void*. Is this then a gcc bug that I should report?
 
Old 08-24-2008, 12:18 PM   #4
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Oh, and in case this is relevant, the code does perform correctly.
 
Old 08-24-2008, 12:28 PM   #5
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
I don't understand this line:
Code:
applets.push_back(((applet_creator)ptr)(*(new Configuration(*backings[id].first, id))));
What type is applets? It looks like you have two conjoined statements as the argument for push_back: ((applet_creator)ptr) doesn't contain a dereference operator, so it has no formal relationship with (*(new Configuration(*backings[id].first, id))) other than that it appears you're using a function pointer as if it were a function, which is probably what the compiler sees.
ta0kira

PS You shouldn't nest the *new operation here. If new fails then you have a problem, though it isn't likely new will fail, which is why you probably haven't seen a problem yet.

Last edited by ta0kira; 08-24-2008 at 12:32 PM.
 
Old 08-24-2008, 12:41 PM   #6
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Applet is an abstract base class for various applets. The goal is be able to load applets from modules at runtime. Each applet is a separate class, whose definition is not present in the main program. Therefore, these applets cannot be 'new'ed, as their types are not yet fixed at compile-time. To solve this, each module exports the symbol "create_applet" a function which takes a Configuration object (we can think of these as perfectly opaque) and returns an Applet*.

"applets" is a vector of Applet*. So if we dissect this line we have, from the inside out:
((applet_creator)ptr) is casting the ptr to applet_creator, the type of the factory function pointer.
(*(new Configuration( ... ))) is passing an argument to that function pointer, a new Configuration object.
(*backings[id].first, id) is irrelevant to this discussion, it's the arguments to the Configuration's constructor
All this is then being given to the push_back method of our vector. This line creates a Configuration object, uses it to instantiate a new Applet via the factory function, then pushes that pointer onto a vector.

Hope that clears that up! Thanks for the help.

Last edited by PatrickNew; 08-24-2008 at 01:23 PM. Reason: said "runtime" but meant "compile-time"
 
Old 08-24-2008, 12:43 PM   #7
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Oh, and the constructor for Configuration never throws, so the only time new would fail is in an out-of-memory scenario. That's not impossible, and I guess I should account for that.
 
Old 08-24-2008, 12:51 PM   #8
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
But you do use a *new pattern in (*(new Configuration(...)). That's where I'm talking about. You missed my question about using a function pointer as a function. Should the cast statement be (*(applet_creator)ptr)? Am I correct in assuming that the error occurs there?
ta0kira

Last edited by ta0kira; 08-24-2008 at 12:54 PM.
 
Old 08-24-2008, 12:54 PM   #9
ErV
Senior Member
 
Registered: Mar 2007
Location: Russia
Distribution: Slackware 12.2
Posts: 1,202
Blog Entries: 3

Rep: Reputation: 62
Quote:
Originally Posted by PatrickNew View Post
The warning I get is that "ANSI C++ forbids casting between pointer-to-object and pointer-to-function".
Why do you want to do this? This makes no sense. You can take function to the class function, by the way, if this is what you want.

Quote:
Originally Posted by PatrickNew View Post
I am casting from a an object- to function-pointer intentionally. The referenced line is pulling a symbol from a dynamically loaded module via dylsym() and casting it to the appropriate function type.
This still doesn't make any sense.
If you want to access object from within loaded module, then add function to the module which will return pointer to an object.
Or access it as void*.

Quote:
Originally Posted by PatrickNew
applets.push_back(((applet_creator)ptr)(*(new Configuration(*backings[id].first, id))));
You probably have memory leak here, because pointer returned by new is lost, so releasing memory might be problematic.
To me it looks like you are trying to do something in a wrong way.
Explain in plain english, what are you trying to achieve.

Last edited by ErV; 08-24-2008 at 12:59 PM.
 
Old 08-24-2008, 01:08 PM   #10
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
@takoira: Oh, I see what you mean. I think that the deference operator on a function pointer is optional. That is, operator() on a function pointer calls the underlying pointer.
http://www.newty.de/fpt/fpt.html#call

I still agree that the nested new's are bad form, and I will fix that. And you asked where the error occurs - it's not an error, just a warning. The code builds and runs fine, this is a more-or-less cosmetic issue. I just want to make the warning message go away the "right way".

@ErV I'm casting a void* to a function pointer because I'm dealing with runtime loadable modules. I can't just give the class a static factory function because the definition of that class doesn't exist in the program. That's what I get from the module, is the pointer to a factory function.
 
Old 08-24-2008, 01:10 PM   #11
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
use reinterpret_cast<>. That'll tell the compiler that you really mean it.

I'll also echo the concerns about *new and the very likely memory leak implied.
 
Old 08-24-2008, 01:19 PM   #12
ErV
Senior Member
 
Registered: Mar 2007
Location: Russia
Distribution: Slackware 12.2
Posts: 1,202
Blog Entries: 3

Rep: Reputation: 62
Quote:
Originally Posted by PatrickNew View Post
@ErV I'm casting a void* to a function pointer because I'm dealing with runtime loadable modules.
Casting void* to function pointer is fine. But you said you wanted to cast pointer to class into pointer to function, which is really strange request.

Quote:
Originally Posted by PatrickNew View Post
I can't just give the class a static factory function because the definition of that class doesn't exist in the program.
What exactly do you get from module? Post it here.

Quote:
Originally Posted by PatrickNew View Post
That's what I get from the module, is the pointer to a factory function.
How is the factory function declared? Post it here.
If it is factory, than it normally should be static class member or non-class-member function, which takes pointer as an argument, or returns pointer to a new object.
 
Old 08-24-2008, 01:21 PM   #13
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
The *new is intentional, and it does not leak. The Applet object created will return a reference to it's Configuration object on request, which is deleted (via the address-of operator) when the Applet is destroyed. As Applet* is an abstract base class, and the factory functions are the only way to instantiate one, there is never an Applet on the stack - they can only be created (and thus destroyed) dynamically, and the program is structured such that all Applets are deleted at one and only one point in the code. There is a class (AppletManager) whose entire purpose is to manage the lifespans of these Applet*'s.

The new snippet is as follows:
Code:
    void* ptr;
    ids[name].second->get_symbol("create_applet", ptr);
    //Create the applet
    Configuration& c = *new Configuration(*backings[id].first, id);
    applet_creator creator = reinterpret_cast<applet_creator>(ptr);
    applets.push_back((*creator)(c));
The warning still appears, this time on the line with the reinterpret_cast. Hrm...
 
Old 08-24-2008, 01:28 PM   #14
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Quote:
Originally Posted by ErV View Post
Casting void* to function pointer is fine. But you said you wanted to cast pointer to class into pointer to function, which is really strange request.
I never had any kind of pointer-to-class. To the best of my knowledge one cannot create a pointer-to-class in ANSI C++.

[QUOTE]What exactly do you get from module? Post it here.[/QUTOE]
Quote:
How is the factory function declared? Post it here.
I get the address of a function with the type defined by this typedef
Code:
typedef Applet* (*applet_creator)(Configuration& );

Quote:
If it is factory, than it normally should be static class member or non-class-member function, which takes pointer as an argument, or returns pointer to a new object.
That's precisely what this is. It's a function which returns a pointer to a new object.
 
Old 08-24-2008, 01:36 PM   #15
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by PatrickNew View Post
The warning still appears, this time on the line with the reinterpret_cast. Hrm...
That's because reinterpret_cast is C++'s "non-C" attempt at a C-cast; you haven't changed anything except for the cast operator used, but both operators are equivalent. Nothing actually happens with reinterpret_cast or a C-cast; you're just telling the compiler that you know what you're doing looks silly but that you want to do it anyway. You could define reinterpret_cast as this:
Code:
template <class Type2, class Type1>
inline Type2 reinterpret_cast(Type1 vValue)
{ return (Type2) vValue; }
Quote:
Originally Posted by PatrickNew View Post
The *new is intentional, and it does not leak.
A leak isn't the problem: if your process runs out of memory, etc. then you'll unconditionally dereference a NULL pointer. In other words, check for NULL between new and *.
ta0kira

PS I don't see any reason why the warning should happen. This similar test works fine even with -Wall:
Code:
void function() {}

int main()
{
	void *pointer = (void*) &function;
	(*(void(*)())pointer)();
}

Last edited by ta0kira; 08-24-2008 at 01:53 PM.
 
  


Reply



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 Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
( C ) How do you declare a function pointer where a parameter is a function pointer? spursrule Programming 5 11-27-2007 07:56 PM
pointer cast c++ santana Programming 10 10-19-2007 07:55 AM
makes pointer from integer without a cast ? hubabuba Programming 2 01-28-2005 05:28 PM
pointer from integer without a cast bcf2 Programming 7 12-30-2004 02:04 PM
makes pointer from interger without a cast y0shi Linux - General 4 10-21-2004 08:17 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 12:03 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration