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 <j...@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 ________ j...@toerring.de > \_______________________________ http://toerring.de > -- -------------------------------------------------------------------------------------------------- “Nothing in all the world is more dangerous than sincere ignorance and conscientious stupidity.” ~ Martin Luther King, Jr
_______________________________________________ PyQt mailing list PyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt