How would I access main.c's global variables from another file, say example.c?
My compiler says undefined identifier without any special accessors, and putting the global variables into a header file included by both files gives me a "multiply-defined identifier" error :-\
Quote from: tA-Kane on June 04, 2003, 04:13 AM
How would I access main.c's global variables from another file, say example.c?
My compiler says undefined identifier without any special accessors, and putting the global variables into a header file included by both files gives me a "multiply-defined identifier" error :-\
You put "extern" declarations for them in the header file. You declare them just like you do in the .c file but you put the word "extern" in front of the declaration. And remove any initializers.
KBNetwork.h
extern unsigned long KBNetStatus;
extern UInt32 OTVersion;
main.c
#include "KBNetwork.h"
KBNetwork.c
#include "KBNetwork.h"
QuoteLink Error: undefined 'KBNetStats' (data)
Referenced from 'KBNetInit()' in KBNetwork.c
Link Error: undefined 'OTVersion' (data)
Referenced from 'KBNetInit()' in KBNetwork.c
I don't think extern is being used properly; I've always seen it be used to identify functions, not variables, and for that matter, it's seemingly always being used to define functions which are stored in an outside library.
Just FYI, you should never EVER use global variables across files. The best way to do that type of thing is with accessor/mutator functions, even though those are very c++-ish :)
Quote from: iago on June 04, 2003, 07:41 AM
Just FYI, you should never EVER use global variables across files. The best way to do that type of thing is with accessor/mutator functions, even though those are very c++-ish :)
I totally disagree. Accessing across files is perfectly sound, as long as you set up the compile environment to keep the object files synchronized (e.g. if you extend a structure definition, both files need to be recompiled or one may behave very oddly). If the designers had meant for you never to access across files, they probably would've made "static" a default.
Kane: you did it right, but you missed a step. Declaring something extern informs the compiler of its type and size (thus suppressing the unknown identifier error), but does not actually allocate storage for it. So, as you posted it, both files know the type and size and both expect a
third party to go to the trouble of storing it. Note that you can declare something extern, then later create it, like so:
extern int myvar;
/* stuff */
int myvar = 0xbaadf00d;
So, what you ought to do here (and I believe Adron mentioned this) is to pick one of the two files and repeat the declaration, without extern. Thus, both files include the header and see the variable declared as extern. One subsequently creates the variable with the non-extern declaration.
Thanks Adron and Kp, this works:
KBNetwork.h
extern unsigned long KBNetStatus;
extern UInt32 OTVersion;
main.c
#include "KBNetwork.h"
KBNetwork.c
#include "KBNetwork.h"
unsigned long KBNetStatus = 0;
UInt32 OTVersion = 0;
Quote from: Kp on June 04, 2003, 01:09 PM
Quote from: iago on June 04, 2003, 07:41 AM
Just FYI, you should never EVER use global variables across files. The best way to do that type of thing is with accessor/mutator functions, even though those are very c++-ish :)
I totally disagree. Accessing across files is perfectly sound, as long as you set up the compile environment to keep the object files synchronized (e.g. if you extend a structure definition, both files need to be recompiled or one may behave very oddly). If the designers had meant for you never to access across files, they probably would've made "static" a default.
Well, it IS perfectly sound from a programming perspective, but it's a problem for the same reason that making member variables in a class public. Nothing is stopping you from doing it, but it's bad practice. I guess this is more of a style thing than anything else, but I tend to (and, for school, have to) follow it.
you shouldn't use global variables ever for any reason! if you declare global variables, anybody who writes code that overlaps with your program can modify that variable.
pass pointers to structs or classes if you have to, it's not that big of a deal.
Quote from: Camel on June 05, 2003, 05:17 PM
you shouldn't use global variables ever for any reason! if you declare global variables, anybody who writes code that overlaps with your program can modify that variable.
Explain?
To quote my OOP prof, who was talking about why you should use private members, "You don't want just anybody playing with your privates"
iago, please sit down, this will be difficult news to tell you.
Your professor does not know it all.
Now that you're in college, you may feel the compulsion to repeat what you've been taught there as "the truth". When it comes to your exams, it is the truth.
Quoteyou shouldn't use global variables ever for any reason! if you declare global variables, anybody who writes code that overlaps with your program can modify that variable.
Now come on, never using global variables ever is just poppycock. Also, the other person who "overlaps with your program" would have to include the file containing the global in some way, or use extern. If this was a problem (which is shouldn't be), there's always namespaces.
Quote from: Grok on June 06, 2003, 12:03 AM
iago, please sit down, this will be difficult news to tell you.
Your professor does not know it all.
Now that you're in college, you may feel the compulsion to repeat what you've been taught there as "the truth". When it comes to your exams, it is the truth.
I actually meant that quote as a joke... "Playing with your privates" ;-)
+1 to iago for the irrelivant privates comment
consider:
struct privates iagos_privates;
versus:
class privatestuff
{
public:
bool touchiagosPrivates(...);
private:
struct privates iagos_privates;
};
void main()
{
class privatestuff iagosPrivateStuff;
}
in the former, anybody can say "extern struct privates iagos_privates;" and then play with iago's privates freely. in the latter, one cannot even look at iago's privates; it's sort of like wearing steel underpants.
Quote from: Camel on June 10, 2003, 05:36 PM
+1 to iago for the irrelivant privates comment
consider:
struct privates iagos_privates;
in the former, anybody can say "extern struct privates iagos_privates;" and then play with iago's privates freely. in the latter, one cannot even look at iago's privates; it's sort of like wearing steel underpants.
Just do this:
static struct privates iagos_privates;
Now the symbol isn't exported, so the linker won't be able to match up other people's references to it. It doesn't protect against other accesses from the same file, but you trust the code in the same file as you - right? :)
Quote from: Kp on June 11, 2003, 12:15 AM
Quote from: Camel on June 10, 2003, 05:36 PM
+1 to iago for the irrelivant privates comment
consider:
struct privates iagos_privates;
in the former, anybody can say "extern struct privates iagos_privates;" and then play with iago's privates freely. in the latter, one cannot even look at iago's privates; it's sort of like wearing steel underpants.
Just do this:static struct privates iagos_privates;
Now the symbol isn't exported, so the linker won't be able to match up other people's references to it. It doesn't protect against other accesses from the same file, but you trust the code in the same file as you - right? :)
I sure as hell don't.. I never know when I'm going to be attempting to screw myself up :-/
Quote from: Kp on June 11, 2003, 12:15 AMJust do this:static struct privates iagos_privates;
Now the symbol isn't exported, so the linker won't be able to match up other people's references to it. It doesn't protect against other accesses from the same file, but you trust the code in the same file as you - right? :)
that isn't the point. the idea is to not allow joe shmoe to modify the data direcly without going through some function that can check the validity of the data. perhaps one wants to pass a string (for the sake of argument, a char array pointer) to the function. rather than just modifying the data directly, one must call the function. the function can check, for example, if the pointer is set to NULL. this way, one need not check if the pointer is null every time he wants to modify the data. this makes for 1) more consise and easier to read code, 2) a little bit of security, 3) a lot less code to change when you decide to convert your char* to an std::string (or simmilar)
the only time where this would be a truely unfavorable approach is when an application becomes so time critical that one should be considering looks into asm to handle one's loops
Quote from: Camel on June 13, 2003, 07:39 AM
Quote from: Kp on June 11, 2003, 12:15 AMJust do this:static struct privates iagos_privates;
Now the symbol isn't exported, so the linker won't be able to match up other people's references to it. It doesn't protect against other accesses from the same file, but you trust the code in the same file as you - right? :)
that isn't the point. the idea is to not allow joe shmoe to modify the data direcly without going through some function that can check the validity of the data.
Unless you make a habit of letting joe shmoe write code in your source file, my solution enforces that. From another file, he *cannot* directly access iagos_privates because its name was never exported (thus he would get a linker error if he tried). If you follow "good" design in laying out your functions, only the accessors/mutators for iagos_privates (I'll let someone else fill in the mutator jokes...) will be in a position to locate that name. Good is, of course, a highly relative idea. IMO, it means (at the least) separating your code across file divisions that help enforce meaning. For instance, putting your GUI code and configuration file reading code in separate files because they have such radically different purposes.
once again you've missed the point. it's not all about security -- in fact, security would be the least of my worries. read my previous post again and comment on more than just the second sentance, plz.
i agree, the first step to making code readable to one's self is to seperate the code, but this can certainly backfire. unless your code looks like:
void main()
{
class myBot;
myBot.GetInfo;
mybot.CreateMainWindow();
myBot.ShowMainWindow();
myBot.BNCS_Connect("useast.battle.net", 6112);
}
then it is almost always intimidating for outsiders seeing the code for the first time. IMO, the most important skill of a good programmer is to be able to write code that's extremely intuitive -- code that doesn't need comments because it explains itself.
Quote from: Camel on June 13, 2003, 04:40 PM
once again you've missed the point. it's not all about security -- in fact, security would be the least of my worries. read my previous post again and comment on more than just the second sentance, plz.
From what I can see, there's nothing in your post that the use of static on the variable declarations would not solve. It could even be solved by just putting a "don't touch" sign on the variables. (i.e. not documenting them as you do the functions)
Besides, no matter what you do, the variables can be modified by joe shmoe if he really wants to.
how many times do i have to say it's not all about security? perhaps i just want to check that i'm not setting some string to null, but i dont want to code it in a billion places. that ALONE is enough reason to use a class.
Now you're just being pissy. What did joe schmoe do to deserve this outburst of attitude?
j/k
Quote from: Camel on June 14, 2003, 07:56 PM
how many times do i have to say it's not all about security? perhaps i just want to check that i'm not setting some string to null, but i dont want to code it in a billion places. that ALONE is enough reason to use a class.
No, it's not. You can use a function to set your variables whether you put them in a class or not.
Camel, not a flame, but FYI:
I don't think you realise the collective experience of the programmers you're arguing with. You're making yourself look pretty stupid.
Especially with that avatar.
/me is not a hypocrite :P
i'm not trying to make a blanket statement that it's always best to use a class, i'm just saying that in most cases where there is pooled code, it's a good idea because it allows more control in one centralized place. i know i wouldnt want to go searching through 50 pages of someone else's code who didnt understand how my struct was *supposed* to be used.
If Joe Shmoe screws something up, that's great. Atleast it's not running on your computer. I say if he isn't smart enough to follow some type of "protocol", then he needs to go back to elementary school. You should not have to put in place extra code to check for stupidity.
Quote from: Camel on June 16, 2003, 09:23 PM
i'm not trying to make a blanket statement that it's always best to use a class, i'm just saying that in most cases where there is pooled code, it's a good idea because it allows more control in one centralized place. i know i wouldnt want to go searching through 50 pages of someone else's code who didnt understand how my struct was *supposed* to be used.
Actually, either you don't have to be searching through 50 pages of someone else's code either way, or you do. If the user is being nice, you don't have to look through the code, because he's using your functions. If the user isn't being nice, he's poking data straight into your classes no matter what you try. And it's probably easier to poke data straight into a class than into a static variable in another file.
adron, you're assuming joe shmoe has malicious intent. maby he just accidently sets some pointer to NULL because he didn't check its value first. then it would be favorable to check if said pointer is NULL not to restrict access (as i said, it has nothing to do with security) but for reliablility (through redundancy)
Frankly, camel is at least partially right here. When you're building a program, unless you are the absolute only one ever using it (and it's rare that you can actually be sure of that), it's best to assume that the potential user of your code is going to do something wrong. The user is a moron: if there's something that can be screwed up, they'll find it, so you'd better make sure there isn't.
On the other hand camel, a lot of your arguments don't really have anything to do with the necessity of using classes. Well-constructed procedural code can accomplish the same thing if you really want it to.
Quote from: Zakath on June 17, 2003, 11:15 PM
On the other hand camel, a lot of your arguments don't really have anything to do with the necessity of using classes. Well-constructed procedural code can accomplish the same thing if you really want it to.
And that's what I (and some others) have been saying all the time. And regardless what Camel is saying, this *does* have to do with security. Not security from people with an intent to damage, but security from mistakes. joe shmoe may ZeroMemory your class or something, and that might cause a lot of trouble. Instead, declare a static variable for your data that needs protection, and there will be no way for him to mess up and zero it out.
Quote from: Adron on June 18, 2003, 07:25 AM
And that's what I (and some others) have been saying all the time. And regardless what Camel is saying, this *does* have to do with security. Not security from people with an intent to damage, but security from mistakes. joe shmoe may ZeroMemory your class or something, and that might cause a lot of trouble. Instead, declare a static variable for your data that needs protection, and there will be no way for him to mess up and zero it out.
i think that's a little far fetched. of course classes aren't going to protect your variables, that wasnt the point. it's just for headache saving.
perhaps we can compromise:
#if Debug
class privatestuff
{
public:
bool touchiagosPrivates(...);
private:
struct privates the_privates;
} iagos_privates;
#else
static struct privates iagos_privates;
#end if
fair?
[edit] renamed iagos_privates::iagos_privates :)