SGI: Development

C/C++: Linker error for static class members

Hey all,

Am bumping up against the limits of my (limited) C/C++ knowledge (again). Perhaps somebody can help?

I'm trying to use libcurl from C++. Being pure C libcurl has no idea about C++'s implicit this pointer, so when used from C++ libcurl's callback fn's need to be defined as static . From what I understand, using the static qualifier turns a C++ member variable/function into one 'owned' by the class rather than an instance of that class (or probably something that the compiler sticks outside of the name-mangled mess of all the instances), which in turn removes the need for a this pointer.

So far so good.

My initial solution was to use a few (evil) global variables (why are they evil? they work and don't cause headaches). But when I move those globals into the class definition as static members, I get:

Code: Select all

ld32: ERROR   33 : Unresolved data symbol "FTP::_state" -- 1st referenced by FTP.o.

on each of the variables I moved into the class definition. However, the staticly defined class-method callback functions have been working from the beginning.

What am I missing here?

J.
:Fuel: redbox 800Mhz 4Gb V12
to make a function in C++ that uses C calling conventions you normally use the extern "C" {} syntax
:PI: :O2: :Indigo2IMP: :Indigo2IMP:
robespierre wrote: to make a function in C++ that uses C calling conventions you normally use the extern "C" {} syntax

Well, the static _functions_ are working just fine. No problems at all. But when I stick the global _variables_ into the private/public sections of the class declaration, that's when I get the ERROR 33's.
:Fuel: redbox 800Mhz 4Gb V12
jimmer wrote: My initial solution was to use a few (evil) global variables (why are they evil? they work and don't cause headaches)

they're not evil, they just can't be predicted well by the compiler so optimizing suffers

Code: Select all

ld32: ERROR   33 : Unresolved data symbol "FTP::_state" -- 1st referenced by FTP.o.

the _state variable of your FTP class is not available to your FTP object file. could you show the FTP class prototypes and one example of using it?
r-a-c.de
foetz wrote: the _state variable of your FTP class is not available to your FTP object file. could you show the FTP class prototypes and one example of using it?


Here you go, the full sources. The issue is in FTP{ .h .C }.

I rolled back the files to the last working versions - ie. the ones without my failed attempts to incorporate the various 'global' variables into the class as static.

Any improvements to the code or tips/comments/suggestions which will improve my coding abilities - the more the merrier :)

J.
:Fuel: redbox 800Mhz 4Gb V12
global variables are considered evil in c++, not c (In c there are pretty much an absolute!) for a number of reasons, mainly they imply bad/non-existant oo design. No access control (any object can access them at any time) not thread safe, namespace pollution.... there is quite a list! I will reiterate though this is from a c++ perspective only.

In c++ world, globals shouldn't really exist as they should be within an object... even if it is a static object called GlobalVariables or something (ContextObjects, singleton... there are a few that can be used). This allows them to be properly and safely managed as desired and not just left out on the pavement for anyone to piss on as they walk by.

However, this is in theory.... in practice I have used globals many a time!

In regards to your code, you have to initialise statics in a source file somewhere...you have only declared FTP::_state, and not defined it anywhere.

In FTP.C, in global scope (i.e above the FTP constructor implementation)

Code: Select all

int FTP::_state = 0;

On another note...

FTP.h

Code: Select all

~FTP(){};
does not need trailing semi-colon... it can become

Code: Select all

~FTP() {}


Not too sure about your typedef struct declaration... 'typedef' is not required, you only need to do this...

Code: Select all

struct TransferInfo
{
...
};


and while we are on the subject of statics, 'const' objects should declared static to stop duplication across contexts. e.g

Code: Select all

const int var

should become

Code: Select all

static const int var


using namespace , is frowned upon as all it does is allows you use std stuff without typying 'std::' in front of it. However it pollutes the namespace and brings in that extra bit of implicit headache when debugging by eye. Explicit usage of std is preffered, or alternatively you can typedef at the top and call your std object whatever you want, plus allowing another object of yours to be called 'string' if desired.... although with small source files its not the end of the world.... but NEVER use using namespace in a header!

Also, I only say this as at work we had a massive argument about this a few years ago.... becareful when using leading underscores for names since this can lead to confusion with certain compilers as preprocessor directives tend to use leading underscores (mainly double leading underscore).

FTP.C
Should this not be FTP.cpp? :)

Hope this helps. rest of the code LGTM
Thank you very very much spiroyster! So nice to get some comments on my code and advice on how to improve it. I'll try your suggestions and see how far I get :)

If anybody else has other ideas/suggestions, please, don't be shy!

J.
spiroyster wrote: FTP.C
Should this not be FTP.cpp? :)

no, uppercase C is fine. in fact i usually advise against using cpp because that's the name of the preprocessor.

otherwise that's a very nice summary spiroyster :-)
however never forget to do things how you get along best as long as it compiles fine and is your project. a lot of conventions have more of a protective reason than something else and the same goes for a lot of c++ "features" in general.
as long as it's your project and your code, if you're fine with declaring namespace std globally for example and it doesn't bite you in the XXX then go for it :P
r-a-c.de
spiroyster wrote: using namespace , is frowned upon as all it does is allows you use std stuff without typying 'std::' in front of it.

Yes doing something like using namespace std; is generally recognized as bad form but I frequently do things like using std::cout; and using std::endl; to avoid the monotony of having to type std:: a million times in front of library function calls. Just my 2 cents YMMV. :mrgreen:
Project:
Temporarily lost at sea...
Plan:
World domination! Or something...
spiroyster wrote: global variables are considered evil in c++, not c (In c there are pretty much an absolute!) for a number of reasons, mainly they imply bad/non-existant oo design.

Took this part of your comments to heart and pulled 'The Gang of Four' off my shelf for the first time since uni (the bill says I bought it in 1997...). Have now re-implemented the FTP class as a Singleton. As you suggested, using a more OO idiom fixed the static/non-static linker thing in one fell swoop. Will refactor the rest of my code to be more OO in design.

Thanks again for taking time to give me your feedback and suggestions. Much appreciated :)
:Fuel: redbox 800Mhz 4Gb V12
Ha yes! sorry didn't mean to come across as a bit of a code nazi :( . I saw the keywords tips/comments/suggestions in jimmers last post and I went into Code Review mode. Replace the words 'should' and 'NEVER' with 'could' and 'AVOID if possible' respectively in my previous post. Also please note that I didn't compile it, just eyeballed it and noticed that your static wasn't defined.

Evil isn't always a bad thing, as I said I have used global variables, and will continue to do so! void* are my posion. I find them extrmamly useful but extrmeley dangerous, use them all the time in my own code but would get lynched at work... and for a very good reason. As foet says pretty much most c++ features and laguange is there to aid in design, implementation and maintainability (the latter of which I do think is lacking in the industry, or at least the places I've worked!)...otherwise we might as well all just write in assembly and be done with it. Just because you can use non-safe types and directly access low-level stuff in C++, does that mean you should if there is another way which fits more in line with the way the tools are designed to be used?. However if it starts to hinder readability, then it should be questioned... why is something designed to aid work, hindering it. Right tool for the right job I believe is the phrase (this should also be applied when I see those boring arguments about which is better C or C++...they are different tools, to be used differently and within different environments/contexts, probably for different reasons) :)

On using namespace , yes smaller personal projects (in which you are the architect, code monkey, tester...and probably user) it's perfectly fine and should be used as a tool to help/speed coding (it could be argued that this is the same with typedefs ). This is definately the case in source files, but in a header with large projects it can be horrible to deal with... well the person who wrote it probably wouldn't think so, but later maintainers may well cry (especially if they have to write implementations/drivers which use pretty the mush the sames types (naming wise)).... same with void* , if I came across code with void* I would not be happy (other than my own ofcourse!). With you in control of your own project this is all moot.

As has been said, at the end of the day use what ever convention you are most comfortable with as this will probably allow you to be most productive. There are very few conventions/idioms that I would recommend against tbh...

</rant>

jimmer wrote:
spiroyster wrote: global variables are considered evil in c++, not c (In c there are pretty much an absolute!) for a number of reasons, mainly they imply bad/non-existant oo design.

Took this part of your comments to heart and pulled 'The Gang of Four' off my shelf for the first time since uni (the bill says I bought it in 1997...). Have now re-implemented the FTP class as a Singleton. As you suggested, using a more OO idiom fixed the static/non-static linker thing in one fell swoop. Will refactor the rest of my code to be more OO in design.

Thanks again for taking time to give me your feedback and suggestions. Much appreciated :)


No problem, glad its working for you! it makes a nice change to look at something else for a change. Yes singletons are great.... singletons, stack objects and cheshire cat are probably my most used patterns (cheshire cat might seem detrimental, but on larger code bases it can reduced compilation times drastically, which on some of the systems I work with can be the difference between an hour and 20 min for an entire rebuild). They are all there to help, and avoid bitting you in the XXXX (<- well put!)

Good luck!