Author | Message | Time |
---|---|---|
tA-Kane | 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 :-\ | June 4, 2003, 9:13 AM |
Adron | [quote author=tA-Kane link=board=5;threadid=1539;start=0#msg11524 date=1054718032] 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] 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. | June 4, 2003, 9:40 AM |
tA-Kane | [code]KBNetwork.h extern unsigned long KBNetStatus; extern UInt32 OTVersion; main.c #include "KBNetwork.h" KBNetwork.c #include "KBNetwork.h"[/code][quote]Link Error: undefined 'KBNetStats' (data) Referenced from 'KBNetInit()' in KBNetwork.c Link Error: undefined 'OTVersion' (data) Referenced from 'KBNetInit()' in KBNetwork.c[/quote] 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. | June 4, 2003, 11:23 AM |
iago | 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 :) | June 4, 2003, 12:41 PM |
Kp | [quote author=iago link=board=5;threadid=1539;start=0#msg11538 date=1054730478] 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]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:[code]extern int myvar; /* stuff */ int myvar = 0xbaadf00d;[/code] 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. | June 4, 2003, 6:09 PM |
tA-Kane | Thanks Adron and Kp, this works: [code]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;[/code] | June 4, 2003, 7:21 PM |
iago | [quote author=Kp link=board=5;threadid=1539;start=0#msg11554 date=1054750189] [quote author=iago link=board=5;threadid=1539;start=0#msg11538 date=1054730478] 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]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. [/quote] 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. | June 5, 2003, 9:54 PM |
Camel | 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. | June 5, 2003, 10:17 PM |
Yoni | [quote author=Camel link=board=5;threadid=1539;start=0#msg11662 date=1054851428] 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. [/quote]Explain? | June 5, 2003, 10:31 PM |
iago | 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" | June 6, 2003, 1:33 AM |
Grok | 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. | June 6, 2003, 5:03 AM |
Moonshine | [quote]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.[/quote] 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. | June 6, 2003, 6:30 AM |
iago | [quote author=Grok link=board=5;threadid=1539;start=0#msg11682 date=1054875805] 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. [/quote] I actually meant that quote as a joke... "Playing with your privates" ;-) | June 7, 2003, 1:37 AM |
Camel | +1 to iago for the irrelivant privates comment consider: [code]struct privates iagos_privates;[/code] versus: [code]class privatestuff { public: bool touchIagosPrivates(...); private: struct privates iagos_privates; }; void main() { class privatestuff iagosPrivateStuff; }[/code] 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. | June 10, 2003, 10:36 PM |
Kp | [quote author=Camel link=board=5;threadid=1539;start=0#msg12034 date=1055284576] +1 to iago for the irrelivant privates comment consider: [code]struct privates iagos_privates;[/code] 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]Just do this:[code]static struct privates iagos_privates;[/code]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? :) | June 11, 2003, 5:15 AM |
iago | [quote author=Kp link=board=5;threadid=1539;start=0#msg12078 date=1055308521] [quote author=Camel link=board=5;threadid=1539;start=0#msg12034 date=1055284576] +1 to iago for the irrelivant privates comment consider: [code]struct privates iagos_privates;[/code] 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]Just do this:[code]static struct privates iagos_privates;[/code]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] I sure as hell don't.. I never know when I'm going to be attempting to screw myself up :-/ | June 11, 2003, 5:35 AM |
Camel | [quote author=Kp link=board=5;threadid=1539;start=0#msg12078 date=1055308521]Just do this:[code]static struct privates iagos_privates;[/code]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] 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 | June 13, 2003, 12:39 PM |
Kp | [quote author=Camel link=board=5;threadid=1539;start=15#msg12259 date=1055507965] [quote author=Kp link=board=5;threadid=1539;start=0#msg12078 date=1055308521]Just do this:[code]static struct privates iagos_privates;[/code]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] 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.[/quote]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. | June 13, 2003, 3:55 PM |
Camel | 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: [code]void main() { class myBot; myBot.GetInfo; mybot.CreateMainWindow(); myBot.ShowMainWindow(); myBot.BNCS_Connect("useast.battle.net", 6112); }[/code] 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. | June 13, 2003, 9:40 PM |
Adron | [quote author=Camel link=board=5;threadid=1539;start=15#msg12284 date=1055540406] 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. [/quote] 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. | June 14, 2003, 11:48 AM |
Camel | 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. | June 15, 2003, 12:56 AM |
Grok | Now you're just being pissy. What did joe schmoe do to deserve this outburst of attitude? j/k | June 15, 2003, 4:29 PM |
Adron | [quote author=Camel link=board=5;threadid=1539;start=15#msg12352 date=1055638593] 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. [/quote] No, it's not. You can use a function to set your variables whether you put them in a class or not. | June 15, 2003, 9:27 PM |
Arta | 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. | June 15, 2003, 9:32 PM |
St0rm.iD | Especially with that avatar. [me=St0rm.iD]is not a hypocrite :P[/me] | June 15, 2003, 11:27 PM |
Camel | 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. | June 17, 2003, 2:23 AM |
TheMinistered | 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. | June 17, 2003, 4:26 PM |
Adron | [quote author=Camel link=board=5;threadid=1539;start=15#msg12475 date=1055816583] 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. [/quote] 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. | June 17, 2003, 5:35 PM |
Camel | 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) | June 18, 2003, 12:16 AM |
Zakath | 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. | June 18, 2003, 4:15 AM |
Adron | [quote author=Zakath link=board=5;threadid=1539;start=15#msg12565 date=1055909705] 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] 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. | June 18, 2003, 12:25 PM |
Camel | [quote author=Adron link=board=5;threadid=1539;start=30#msg12576 date=1055939141] 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] 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: [code]#if Debug class privatestuff { public: bool touchIagosPrivates(...); private: struct privates the_privates; } iagos_privates; #else static struct privates iagos_privates; #end if[/code] fair? [edit] renamed iagos_privates::iagos_privates :) | June 18, 2003, 6:53 PM |