[prev in list] [next in list] [prev in thread] [next in thread]
List: pykde
Subject: Re: [PyQt] Simple C++ example has undefined symbol
From: Gary Fisher <gefisher.net () gmail ! com>
Date: 2012-01-25 14:08:23
Message-ID: CALhunyZRPLRZGrBQHMK3=TXX+EnX=-bOR1UaM0SRtRhP5YKW_Q () mail ! gmail ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
Hi Jens,
I want to thank you very much for all your help and especially your
patience.
Everything is working perfectly now.
I apologize for the mixed up code...far too much C and not enough C++ in
combination with the old adage "Haste makes waste" !!!
Happy New Year Jens.
Gary ---
On Sun, Jan 22, 2012 at 1:20 PM, Jens Thoms Toerring <jt@toerring.de> wrote:
> Hi Gary,
>
> On Sun, Jan 22, 2012 at 11:57:44AM -0500, Gary Fisher wrote:
> > >>> What does "return (static char *)Null" mean?
> >
> > My mistake...I meant "return (const char *)Null" ... not static....and
> yes
> > I do believe NULL is used in C++. At least the compiler didn't witch at
> me
> > for it.
>
> There's still no reason for the cast. And while you use 'NULL'
> in C quite often it's frowned upon in C++. All you really need
> is
>
> return 0;
>
> Since the compiler knows that the function returns a 'const char *'
> it will automatically do the conversion. By casting (and then
> even using a C-style cast, which is strongly discouraged in C++)
> you tell the compiler "I know better than you" and you shouldn't
> do that unless there's something the compiler can't figure out
> on his own since a) you keep the compiler from explaining about
> stuff that shouldn't/can't be done (don't see compiler complaints
> as a nuisance but as a valuable help you to write correct pro-
> grams) and b) you make the next person reading your code wonder
> what this is all about.
>
> > When I use "nm -C libword.so" on my little wrapped library I see nothing
> in
> > the output to suggest a "word" class or a "reverse" method.
>
> And that's at the very heart of your problem: the symbols needed
> by the wrapper script don't exist in 'libword.so'. Rhe reason is
> that there's not the slightest bit of necessity for the compiler/
> linker to put them in there: you have a class declared with in-
> lined methods that is never used anywhere. So there's no reason
> to use the class for anything and it simply gets thrown out.
>
> Every program using your library would include a header file for
> the library that defines the interface. And while doing so it
> would see the declaration of the class and would construct it's
> own version of the class when it's needed.
>
> I'm a bit at a loss at understanding how you got your SIP wrapper
> to work without a header file, but that's another topic;-)
>
> The quick fix is to simply splitting the word.cpp file up into
> two parts, the necessary header file with the class declaration
> and a cpp file with the function definitions. I.e. something
> like this:
>
> ------- word.hpp -----------------------------
> #ifndef WORD_HPP_
> #define WORD_HPP_
>
> class Word {
> public:
>
> Word( const char * w );
>
> const char * reverse( );
>
> private:
>
> const char * the_word;
> };
>
> #endif
> ------- word.cpp -----------------------------
> #include "word.hpp"
>
> Word::Word( const char * w ) :
> the_word( w )
> { }
>
> const char *
> Word::reverse( )
> {
> return 0;
> }
> ----------------------------------------------
>
> BTW: don't forget the 'public:' in the class!
>
> If you now compile this into a shared library it will con-
> tain both the symbols for the constructor and the reverse()
> method. And within the SIP wrapper you include the 'word.hpp'
> header file.
>
> However, when
> > I run "nm -C word.so" against the library generated by make I get things
> > like:
> >
> > 000021b4 d methods_Word
> > U Word::Word(char const*)
> > U Word::reverse() const
> >
> > among other things.
>
> Yes, the 'word.so' library needs those symbols and expects
> them in one of the libraries it was linked with, but they
> aren't anywhere. That will be only noticed when Python tries
> to load the 'word.so' library and thus it fails.
>
> BTW, the code in your program looks a bit broken.
>
> > class Word {
> > const char *the_word;
> > // const char *the_reverse;
> > char buffer[20], *pb;
> >
> > int i, len;
> >
> > Word( const char *w) {
> > the_word = w;
> > }
>
> Do you realize that 'the_word' is now set to some memory
> that doesn't belong to this class? It looks as if you
> would like to store a word using this class, but that's
> not what you do - all you keep is a pointer to some
> string somewhere else in memory (and not owned by the
> class instance). And if this memory is used for something
> else then the 'the_word' pointer will point to memory that
> doesn't contain a string anymore. I guess you're coming from
> languages where memory allocation is done for you in the
> background (like in Python), but if you write in C++ (or C)
> you will have to be very careful to do the right thing with
> memory, e.g. just holding a pointer to some memory doesn't
> make it "yours" - you have to ensure that nothing else will
> fiddle with the memory pointed to.
>
> > const char *reverse () {
> >
> > return (const char *) NULL;
> >
> > /************************
> > len = strlen(the_word);
> > strcpy (buffer, the_word);
>
> What happens if what 'the_word' points to is longer than 19
> chars? You write past the end of buffer with unforseeable
> effects. In the worst case it even might seem to work at
> firt until some strange and hard to trace erros show up
> much later...
>
> > pb = (char *)the_word;
>
> That's exactly one of the places were a cast shouldn't be
> used. 'the_word' points to memory you are not allowed to
> change. And to get around this you need the cast. So you're
> now operating directly on the memory where your word is
> stored which could reside in read-only memory.
>
> > for (i=len-1 ; i>=0 ; i--) {
> > *pb = buffer[i];
> > pb++;
> > }
>
> > *pb = '\0';
> >
> > return the_word;
> > }
> > };
>
> Here's some way you could do it (but note, I didn't carefully
> check everything):
>
> ------- word.hpp -----------------------------
> #ifndef WORD_HPP_
> #define WORD_HPP_
>
> #include <cstring>
>
> class Word {
> public:
>
> Word( const char * w );
>
> ~Word( );
>
> const char * reverse( );
>
> private:
>
> char * the_word;
> };
>
> #endif
> ------- word.cpp -----------------------------
> #include "word.hpp"
>
> Word::Word( const char * w )
> {
> the_word = new char [ ( w != 0 ? strlen( w ) : 0 ) + 1 ];
>
> if ( w != 0 )
> strcpy( the_word, w );
> else
> *the_word = '\0';
> }
>
> Word::~Word( )
> {
> delete [ ] the_word;
> }
>
> const char *
> Word::reverse( )
> {
> char *ps = the_word,
> *pe = the_word + strlen( the_word );
>
> while ( ps < pe )
> {
> char tmp = *ps;
> *ps++ = *pe;
> *pe-- = tmp;
> }
>
> return the_word;
> }
> ----------------------------------------------
>
> But since you write C++ it is probably nuch more reasonable
> (and safer) to use the std::string class instead of creating
> a probably inferior and slower version on your own;-) And all
> this is very C-ish, for example in C++ you would rather return
> a Word instance from the reverse() method instead of a pointer
> to something in the innards of the class...
>
> Regards, Jens
> --
> \ Jens Thoms Toerring ________ jt@toerring.de
> \_______________________________ http://toerring.de
>
--
--------------------------------------------------------------------------------------------------
“Nothing in all the world is more dangerous than sincere ignorance and
conscientious stupidity.”
~ Martin Luther King, Jr
[Attachment #5 (text/html)]
Hi Jens,<div><br></div><div>I want to thank you very much for all your help and \
especially your patience.</div><div><br></div><div>Everything is working perfectly \
now.</div><div><br></div><div>I apologize for the mixed up code...far too much C and \
not enough C++ in combination with the old adage "Haste makes waste" \
!!!</div> <div><br></div><div>Happy New Year Jens.</div><div><br></div><div> \
Gary ---</div><div><br></div><div><br></div><div><br><br><div class="gmail_quote">On \
Sun, Jan 22, 2012 at 1:20 PM, Jens Thoms Toerring <span dir="ltr"><<a \
href="mailto:jt@toerring.de">jt@toerring.de</a>></span> wrote:<br> <blockquote \
class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex">Hi Gary,<br> <div class="im"><br>
On Sun, Jan 22, 2012 at 11:57:44AM -0500, Gary Fisher wrote:<br>
> >>> What does "return (static char *)Null" mean?<br>
><br>
> My mistake...I meant "return (const char *)Null" ... not static....and \
yes<br> > I do believe NULL is used in C++. At least the compiler didn't \
witch at me<br> > for it.<br>
<br>
</div>There's still no reason for the cast. And while you use 'NULL'<br>
in C quite often it's frowned upon in C++. All you really need<br>
is<br>
<br>
return 0;<br>
<br>
Since the compiler knows that the function returns a 'const char *'<br>
it will automatically do the conversion. By casting (and then<br>
even using a C-style cast, which is strongly discouraged in C++)<br>
you tell the compiler "I know better than you" and you shouldn't<br>
do that unless there's something the compiler can't figure out<br>
on his own since a) you keep the compiler from explaining about<br>
stuff that shouldn't/can't be done (don't see compiler complaints<br>
as a nuisance but as a valuable help you to write correct pro-<br>
grams) and b) you make the next person reading your code wonder<br>
what this is all about.<br>
<div class="im"><br>
> When I use "nm -C libword.so" on my little wrapped library I see \
nothing in<br> > the output to suggest a "word" class or a \
"reverse" method.<br> <br>
</div>And that's at the very heart of your problem: the symbols needed<br>
by the wrapper script don't exist in 'libword.so'. Rhe reason is<br>
that there's not the slightest bit of necessity for the compiler/<br>
linker to put them in there: you have a class declared with in-<br>
lined methods that is never used anywhere. So there's no reason<br>
to use the class for anything and it simply gets thrown out.<br>
<br>
Every program using your library would include a header file for<br>
the library that defines the interface. And while doing so it<br>
would see the declaration of the class and would construct it's<br>
own version of the class when it's needed.<br>
<br>
I'm a bit at a loss at understanding how you got your SIP wrapper<br>
to work without a header file, but that's another topic;-)<br>
<br>
The quick fix is to simply splitting the word.cpp file up into<br>
two parts, the necessary header file with the class declaration<br>
and a cpp file with the function definitions. I.e. something<br>
like this:<br>
<br>
------- word.hpp -----------------------------<br>
#ifndef WORD_HPP_<br>
#define WORD_HPP_<br>
<br>
class Word {<br>
public:<br>
<br>
Word( const char * w );<br>
<br>
const char * reverse( );<br>
<br>
private:<br>
<br>
const char * the_word;<br>
};<br>
<br>
#endif<br>
------- word.cpp -----------------------------<br>
#include "word.hpp"<br>
<br>
Word::Word( const char * w ) :<br>
the_word( w )<br>
{ }<br>
<br>
const char *<br>
Word::reverse( )<br>
{<br>
return 0;<br>
}<br>
----------------------------------------------<br>
<br>
BTW: don't forget the 'public:' in the class!<br>
<br>
If you now compile this into a shared library it will con-<br>
tain both the symbols for the constructor and the reverse()<br>
method. And within the SIP wrapper you include the 'word.hpp'<br>
header file.<br>
<div class="im"><br>
However, when<br>
> I run "nm -C word.so" against the library generated by make I get \
things<br> > like:<br>
><br>
> 000021b4 d methods_Word<br>
> U Word::Word(char const*)<br>
> U Word::reverse() const<br>
><br>
> among other things.<br>
<br>
</div>Yes, the 'word.so' library needs those symbols and expects<br>
them in one of the libraries it was linked with, but they<br>
aren't anywhere. That will be only noticed when Python tries<br>
to load the 'word.so' library and thus it fails.<br>
<br>
BTW, the code in your program looks a bit broken.<br>
<br>
> class Word {<br>
> const char *the_word;<br>
> // const char *the_reverse;<br>
> char buffer[20], *pb;<br>
><br>
> int i, len;<br>
><br>
> Word( const char *w) {<br>
> the_word = w;<br>
> }<br>
<br>
Do you realize that 'the_word' is now set to some memory<br>
that doesn't belong to this class? It looks as if you<br>
would like to store a word using this class, but that's<br>
not what you do - all you keep is a pointer to some<br>
string somewhere else in memory (and not owned by the<br>
class instance). And if this memory is used for something<br>
else then the 'the_word' pointer will point to memory that<br>
doesn't contain a string anymore. I guess you're coming from<br>
languages where memory allocation is done for you in the<br>
background (like in Python), but if you write in C++ (or C)<br>
you will have to be very careful to do the right thing with<br>
memory, e.g. just holding a pointer to some memory doesn't<br>
make it "yours" - you have to ensure that nothing else will<br>
fiddle with the memory pointed to.<br>
<br>
> const char *reverse () {<br>
><br>
> return (const char *) NULL;<br>
><br>
> /************************<br>
> len = strlen(the_word);<br>
> strcpy (buffer, the_word);<br>
<br>
What happens if what 'the_word' points to is longer than 19<br>
chars? You write past the end of buffer with unforseeable<br>
effects. In the worst case it even might seem to work at<br>
firt until some strange and hard to trace erros show up<br>
much later...<br>
<br>
> pb = (char *)the_word;<br>
<br>
That's exactly one of the places were a cast shouldn't be<br>
used. 'the_word' points to memory you are not allowed to<br>
change. And to get around this you need the cast. So you're<br>
now operating directly on the memory where your word is<br>
stored which could reside in read-only memory.<br>
<br>
> for (i=len-1 ; i>=0 ; i--) {<br>
> *pb = buffer[i];<br>
> pb++;<br>
> }<br>
<br>
> *pb = '\0';<br>
><br>
> return the_word;<br>
> }<br>
> };<br>
<br>
Here's some way you could do it (but note, I didn't carefully<br>
check everything):<br>
<br>
------- word.hpp -----------------------------<br>
#ifndef WORD_HPP_<br>
#define WORD_HPP_<br>
<br>
#include <cstring><br>
<br>
class Word {<br>
public:<br>
<br>
Word( const char * w );<br>
<br>
~Word( );<br>
<br>
const char * reverse( );<br>
<br>
private:<br>
<br>
char * the_word;<br>
};<br>
<br>
#endif<br>
------- word.cpp -----------------------------<br>
#include "word.hpp"<br>
<br>
Word::Word( const char * w )<br>
{<br>
the_word = new char [ ( w != 0 ? strlen( w ) : 0 ) + 1 ];<br>
<br>
if ( w != 0 )<br>
strcpy( the_word, w );<br>
else<br>
*the_word = '\0';<br>
}<br>
<br>
Word::~Word( )<br>
{<br>
delete [ ] the_word;<br>
}<br>
<br>
const char *<br>
Word::reverse( )<br>
{<br>
char *ps = the_word,<br>
*pe = the_word + strlen( the_word );<br>
<br>
while ( ps < pe )<br>
{<br>
char tmp = *ps;<br>
*ps++ = *pe;<br>
*pe-- = tmp;<br>
}<br>
<br>
return the_word;<br>
}<br>
----------------------------------------------<br>
<br>
But since you write C++ it is probably nuch more reasonable<br>
(and safer) to use the std::string class instead of creating<br>
a probably inferior and slower version on your own;-) And all<br>
this is very C-ish, for example in C++ you would rather return<br>
a Word instance from the reverse() method instead of a pointer<br>
to something in the innards of the class...<br>
<div class="HOEnZb"><div class="h5"><br>
Regards, Jens<br>
--<br>
\ Jens Thoms Toerring ________ <a \
href="mailto:jt@toerring.de">jt@toerring.de</a><br> \_______________________________ \
<a href="http://toerring.de" target="_blank">http://toerring.de</a><br> \
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- \
<br><div>--------------------------------------------------------------------------------------------------</div><div><span \
style="font-family:Arial,sans-serif"><br> </span></div><div>
<p style="margin-top:0.19in;margin-bottom:0.19in;background:#ffffff">
<font color="#333333">“<font face="Arial, sans-serif"><font>Nothing
in all the world is more dangerous than sincere ignorance </font></font></font><span \
style="font-family:Arial,sans-serif;color:rgb(51,51,51)">and conscientious \
stupidity.”</span></p> <p \
style="margin-top:0.19in;margin-bottom:0.19in;background:#ffffff"> <font face="Arial, \
sans-serif"><font> ~ Martin Luther King, \
Jr</font></font></p></div><div><p></p></div><font size="3" face="Times New Roman">
</font><br>
</div>
_______________________________________________
PyQt mailing list PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic