Global variables - Evil or not - Page 1
Forum section: electronics / general

author: Jester
author_rank: Frequent Contributor
timestamp: October 20, 2022, 05:47:08 pm
content: Context:1) I'm not a programmer I just dabble in C and c++ to a small extent.2) Embedded application running on a smallish uC for example a small sub module in a automobile, for example: bool wipersOn = false;I appreciate a global variable in some large program for some large company for example American Airlines would probably be a really bad idea.The moment you google "global variable" half the comments are DON'T DO IT you will burn in hell.I have used global variables forever and have never had any issues. Am I missing something?

author: JPortici
author_rank: Super Contributor
timestamp: October 20, 2022, 05:58:48 pm
content: most of my global variables are actually global so that i can inspect them at any time (so are declared global for convenience)a little few are actually global so they can be accessed easily, but they always are written by one process, read by many... or the processes that can perform a write are not preempted so there is no chance that two writes happen simultaneously.The problem as i understand it is when the global variable is read while it's being written too, or it can be written by two or more actors. Especially if the read/write is not atomic (think reading/writing 32bit on a 8/16 bit machine) If you can make it sure that it doesn't happen, then no issue for me.the DON'T DO IT is because too many programmers don't understand this simple concept (with not so simple consequences)And writing accessory functions can have other benefits as well, such as including the range check for the new valueSome times you cannot escape from globals anyway (shared memory, memory at fixed locations, ...)

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 20, 2022, 06:03:28 pm
content: Quote from: Jester on October 20, 2022, 05:47:08 pmyes you are missing something... try to program a little bit larger. for example try to create a Windows GUI library for embedded MCU handling lots of messagings, events, interrupts etc. i recommend do it for PC where you can program larger all you like at virtually unlimited resources. at one point as your program grows and need maintenance and bugs fixes, you'll see why. this rule doesnt apply to small program. the devil is actually in yourself, it hasnt come out yet. if you can appreciate why people invented OOP (and modular subroutines much earlier) you will understand why. its quite difficult to explain to you in short sentences what an elephant is when you havent seen one.

author: Jester
author_rank: Frequent Contributor
timestamp: October 20, 2022, 06:05:48 pm
content: Quote from: Mechatrommer on October 20, 2022, 06:03:28 pmIf you are going to quote me, please don't selectively hide the part of the quote that applies to my question.Context:1) I'm not a programmer I just dabble in C and c++ to a small extent.2) Embedded application running on a smallish uC for example a small sub module in a automobile, for example: bool wipersOn = false;

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 20, 2022, 06:11:47 pm
content: i dont quote what is irrelevant. or what that doesnt make any difference from the important fact that you are working on small system (or just working). so less chance for you to wander, we encountered such situation may times. but if you dont like my comment, just ask to delete it i will gladly do. you can get what you are missing (or not missing at all) from somebody else.

author: ataradov
author_rank: Super Contributor
timestamp: October 20, 2022, 06:13:46 pm
content: There is nothing wrong with use of global variables where justified. And in small embedded systems it is justified a lot.Quote from: Jester on October 20, 2022, 06:05:48 pmIn automotive environment it is a bit harder, since you will also start running into MISRA-C limitations. MISRA-C recommends to avoid global variables and make sure that the variables are declared in a scope that minimizes their visibility. But if you build your application around global variables, then global visibility becomes necessary.

author: tggzzz
author_rank: Super Contributor
timestamp: October 20, 2022, 06:28:58 pm
content: Quote from: Jester on October 20, 2022, 06:05:48 pmSuch selective quoting seems to be happening more frequently on this forum at the moment. It is often accompanied by strawman arguments deployed for a variety of reasons. IMNSHO such tactics should be called out for what they are, lest too many contributors think it is acceptable.IMNSHO the alternative is to allow conversations' value to be degraded, and hence to the degradation of the overall utility, civility and friendliness of this forum. That would be a pity.N.B. mechatrommer's specific post snipped because I am making a more general point than that specific post.

author: magic
author_rank: Super Contributor
timestamp: October 20, 2022, 06:48:25 pm
content: Quote from: Jester on October 20, 2022, 05:47:08 pmYes, dependency injection

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 20, 2022, 07:15:09 pm
content: Quote from: tggzzz on October 20, 2022, 06:28:58 pmhe's asking something that is not his problem. when in small uC people talk about global variable go to hell? is like asking "people said using roger laminate pcb is better than FR4. i've been using FR4 with my small arduino fine, whats i'm missing?" and if someone posts 999 lines of irrelevant/useless statements and only one of related/usefull point of interest, should we quote/duplicate all 1000 lines of almost all useless points? where is the "doing more, with less"?

author: tggzzz
author_rank: Super Contributor
timestamp: October 20, 2022, 07:27:06 pm
content: Quote from: Mechatrommer on October 20, 2022, 07:15:09 pmHe stated accurately accurately the context which he felt should have been included.I copied that context.You have omitted both.You have made a completely different point which isn't relevant to that.You have thereforeagainomitted relevant context.You have thereforeagainraised a strawman argument.And that is despite my specifically stating that I was making ageneralpoint,nota specific point about your post.Remarkable.

author: MikeK
author_rank: Super Contributor
timestamp: October 20, 2022, 07:27:16 pm
content: If you're not using that much RAM in your application there's no reason to limit your globals. You need to avoid globals when memory use and management become an issue. If you're fine with using globals, keep doing it until you run into problems.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 20, 2022, 07:36:37 pm
content: Quote from: tggzzz on October 20, 2022, 07:27:06 pmeverybody can read his context... and here again if i want to make more into context so it can be clearer to you (i dont have to duplicate contexts that have been duplicated many times)..Quote from: Jester on October 20, 2022, 05:47:08 pmyou see, he have his stated context at the top, and then he claimed he googled, and found something that is weird. i highly suspect the answer he got from google are for entirely different context (or from some clueless posters). not for his specific context. prove me wrong. i gave you analogy (about Roger vs FR4 in case you missed that).

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 20, 2022, 08:09:14 pm
content: As with anything else, the crux of the matter is not whether you should or should not use them, but why, how and when.Since "DON'T DO IT you will burn in hell." doesn't answer any of that, you guessed it right, it's useless.To start the thought process, you must begin with the distinction between declaring globals for the static allocation of state data and *accessing* globals directly in functions without passing them around as parameter. The two are orthogonal, yet many, especially beginners, will confuse the two in nice chunks of spaghetti code.- For the former, one way or another you will have to use global variables, unless you are OK with using dynamic allocation on the heap (which is usually not a good idea at all on small MCUs) or maybe even on the stack (for instance, if you allocate local variables in your main() function to store global state, why not - it may just unnecessarily eat up stack space which is usually very limited on small MCUs.)- For the latter, you can absolutely use global variables while limiting a direct access to them to the very bare minimum and otherwise passing them as parameters to functions, or pointers to them. This is by far the preferred way of doing it unless you like spaghetti. (It's good as a dish, not so much for software.) Doing that will tremendously help 1/ maintaining code and making it scalable, 2/ verify and validate code.

author: AndyBeez
author_rank: Frequent Contributor
timestamp: October 20, 2022, 08:12:22 pm
content: For 'production' programming - in any language - you should be thinking about keeping your variables in some kind ofData Structure. A data structure acts like a master collection of variables withglobal scope.Defined either as an array, or a class with getter and setter methods, a data structure is a means of storing values so they can be used by the run time, but keep them together in their own memory bear pit.In your example, the wiper control function might accessVehicle.Wippers.SpeedorVehicle.Wippers.Clean. The lighting control function usesVehicle.CabLight.Mode. But every value is inside theVehicleglobal class. Whether these individual values are Booleans, Strings, Numerics, Enumerations - or even whole functions - that's up to you.For code maintenance, holding values in an organised data structure, rather than a splurge of local and global scopes variables referenced by *&pointers, makes for adding and subtracting values a lot less than evil

author: tggzzz
author_rank: Super Contributor
timestamp: October 20, 2022, 08:29:01 pm
content: Quote from: Mechatrommer on October 20, 2022, 07:36:37 pm... and there you go again.'Nuff said.

author: RoGeorge
author_rank: Super Contributor
timestamp: October 20, 2022, 08:33:29 pm
content: Quote from: Jester on October 20, 2022, 05:47:08 pmYes, but not about programming, it's something else much deeper:There is no such thing as (standalone) Good or Evil.These concepts of Good and Evil only makes sense in relation to a goal. What helps with the given goal is considered Good, what stands against is Evil. What is Good for one can be Evil for other.About global variables, if they help your code, they are Good, if they create problems, they are Evil.Sometimes they are considered bad practice because people often forget about them, or are not told about them (in bigger projects) so they reuse that variable name, and thus they create a mess hard to debug.In embedded programming, where each byte and each clock cycle counts, and where the stack memory is usually very small, the tale about global variable is quite contrary: Global variables are preferred, because they can make the code shorter and faster.

author: coppice
author_rank: Super Contributor
timestamp: October 20, 2022, 08:36:27 pm
content: Global variables easily become a religious issue, like many programming topics. There is nothing fundamentally wrong with global variables. Some things really are truly global, and there is no point in treating them any other way. Things you initialise at startup, and will never change during the runtime of the program, have no reason to be treated as anything but global variables. The problems come not from their use, but their overuse.

author: langwadt
author_rank: Super Contributor
timestamp: October 20, 2022, 08:45:34 pm
content: Quote from: coppice on October 20, 2022, 08:36:27 pmyeh, all the IO and peripheral registers are global ..

author: CatalinaWOW
author_rank: Super Contributor
timestamp: October 20, 2022, 10:43:11 pm
content: A simple example shows how many rabbit holes this question can dive into. Take one of the physical constants. Pi. Seems like a perfect candidate for a global level. There are languages in which is made available as a language define value. There shouldn't be any issues with someone writing while someone else is reading.But dig a little deeper. Some parts of your application may need full double precision or greater. Others want want less for speed or memory efficiency, or even just to assure consistency with another source. I have even seen applications where using integers and the 22/7 approximation makes sense. If any or all of these happen the benefit of global application diminishes and may go negative.

author: brucehoult
author_rank: Super Contributor
timestamp: October 20, 2022, 10:57:26 pm
content: Quote from: Jester on October 20, 2022, 05:47:08 pmThere are two different issues:1) static lifetime for a variable. This is absolutely necessary for statefull programming. Sometimes these variables may even need to be in EEPROM rather than RAM so they survive reset/power off.2) too much visibility of a static variable, such that you can't easily know which parts of the program read and/or write to it.Tools such as an IDE or even simply grep on the command line can help you find all the places a variable is used.If a variable is used in a single function then it can be declared as "static" inside that function.If a variable is used in a small number of functions then it and those functions can be gathered in a single C file and the variable global in that file but marked as static. Other C files will then not be able to refer to it by accident.In a small program none of this is a problem. The potential problems arise in large programs with poor modularity discipline.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 20, 2022, 11:25:10 pm
content: 0. It doesn't matter, everything goes, it's C, do whatever you like!1. Who are youreallywriting for?If for the machine, do whatever you like.If for other programmers -- give some consideration to what they will find understandable.This includes your own future self! An issue you may've noticed already, or maybe not if you're still fairly new to this, or just very consistent in your writing style. (Which could kinda mean two things: that you're very consistent and familiar with your own dialect (or many dialects), or that you indeed format and comment things well already. Preferably, the formeristhe latter.)2. What is the purpose of this issue?Globals are readable and writable by any module in the system, whether they "should" be able to or not. Mind, that means semantically: C of course doesn't give a shit if you trample random memory, that's your own prerogative. It's about visibility and scoping, and how much interface is exposed between modules.Note that, depending on compiler version and declarations, globals may be automatically shared, or not. In GCC < 8 I believe?, they were shared; after, not. Scope can be controlled by prefixingstatic(local to module) orextern(shared).The temptation is that, with globals shared and scoped, they become part of the interface, whether intended or not, and complexity grows massively. Every outside reference to a variable, is one more reference you need to keep track of, with respect to state changes within the module (if indeed the variables declared within it are mostly/entirely used locally -- you don't have to, of course..!), the consistency thereof, and what ways the module can be interacted with.Ultimately, what this drives towards is the matter of reusability, that a module should be largely self-contained, expose only its documented interfaces, and enforce that as such.A recent example I used is this,https://github.com/cwalter-at/freemodbus/tree/master/modbusIt's fairly old and mature, actively maintained (well, there are a couple PRs sitting around for a few years, but last I looked, all quite minor and easily implemented yourself), and very modular. You implement the physical/interface bits in theportfiles, implement the callbacks (messages translated into read/write commands, you implement the read/writing yourself), pick the interface you want (on init), then poll in amain()loop. The code is fairly compact, straightforward -- Modbus is a pretty thin and simple stack, but a stack it is -- and easy enough to understand. So, I think it's a good illustration of how convenient this style of design and organization is.Which leads into:3.https://en.wikipedia.org/wiki/Dependency_injectionAs mentioned above, it's another design pattern that can help simplify things.The apparent downside for embedded purposes is, all this boilerplate doesn't matter, you're only ever going to use one configuration, and you're checking memory regularly (well, maybe) and it's all flat in the end, who cares.Well, the overhead is small; in C, the function pointers used during MBinit() for example, will always emit a load, call (register indirect) operation (or, I think so, anyway?). Distinctly slower than absolute call, let alone inlining the thing whole. But how often are you calling MBinit()? Just once? Yeah who cares about an extra five or 20 cycles. And the polling is done, whatever, say every millisecond, what's another couple dozen cycles on that, who cares?The worst part is probably interrupts, which are often written as callbacks in these sorts of things (see also: STM32 HAL and the like), so all registers on the ABI's clobber list must be saved and restored around the call. But here still, it needn't be a problem. For Modbus at least, conventional baud rates are slow (9600, 19200...) so few interrupts can fire per second. YMMV for whatever kind of module, of course, but the point is, many things aren't performance sensitive, or nearly as much as you're apt to think in the embedded world.In C++, more of these are likely to be optimized down, AFAIK, so, a constant function pointer at compile-time may end up inlined, say. In that case, there's literally no downside.Exposure to newer languages probably helps out as well. Being familiar with say Java Objects (everything is an Object, no pointers, only references), or lambdas or other functional things (Factory design pattern; passing functions as parameters or objects; etc.), gives you a higher level perspective that you'd never realize deep down in the trenches of plain C. Even if you're never using the full form of those structures, knowing that they're there, and that you could express what you're doing as a reduced form of one of these constructs -- can help organizing things.Tim

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 20, 2022, 11:26:14 pm
content: there are enough materials in the net to educate about the why not to use them (on certain programming scale/topology/hierarchy/concept/design) this is more "theoretical" or "logical" rather than trivial matter such as to save memory space or make things faster to run etc, certainly not in the context of OP. if you happened to buy an academic books about teaching you into larger scale software/data design/structure, you will sometime see this hinted by the author who happened to be a professor or at the same level as people like Mr Bjarne. those who have been bitten know how to appreciate and know this is something for real albeit intangible with no physical appearance, those who have a hard time understanding the why, that means its none of their business, they can do whatever they like and certainly nothing will go wrong... i bet their software is simple enough to maintain no matter how complex they think it might be...https://www.tutorialspoint.com/Why-should-we-avoid-using-global-variables-in-C-Cplusplus

author: mac.6
author_rank: Regular Contributor
timestamp: October 22, 2022, 08:13:19 am
content: In embedded system, especially constrained ones, global variable are mostly required.But what matters is how you use them.Direct access to global variable is the culprit. this is the start of the spaghetti code, all your code is tied by the globals references.So better use a global pointer/structure for one or more global context, then a bunch of accessor function.This way you can easilly control access and reuse your code.All the fuss about visibility/abstraction only matters if you share code or doing libraries. If you controll 100% of your code and partition it correctly it doesn't matter at all.

author: Siwastaja
author_rank: Super Contributor
timestamp: October 22, 2022, 09:14:59 am
content: Terminology:NOT global, but file-scope static variable:Code:file.c:static int var; // accessible to all functions in file.cActual global:Code:file.h:extern int var; // include file.h to access var from any modulefile.c:int var;You can also sayvaris now part of the interface of this module.File-scope statics can't be realistically avoided in C, they store shared state between the module functions. Equivalent to private member variables in C++ class.Actual globals can, and maybe should be avoided, but sometimes they are just the easiest way and they don't magically transform your code into shit. If you find yourself using globals all the time, you can ask yourself if you could abstract the functionality better so that, for example, uart.c does all UART-related things and interface only consists of a few functions, not variables.

author: ejeffrey
author_rank: Super Contributor
timestamp: October 22, 2022, 05:51:34 pm
content: There are a couple of problems with global variables, how big of a problem they are depend on your situation.The first is name collisions and is really specific to C which has no good namespace support. Almost any other language in common use has either default or optional module level namespaces. This allows you to make a module variable visible globally but require it to be qualified by a module name when uses in other modules. The standard way to avoid this in C is to use prefixes which works OK. If you are going to use globals in anything reusable or more than a handful of .c files in a single directory I strongly recommend doing this.The second is that you lose control over how a variable is used. For instance if you want to make a project thread safe, you might need to add locks. If you have accessors you have a way to do this that is much simpler than if you have to change every access. Global variables can also have issues with order of initialization. If a global variable has complex initialization it can be difficult to ensure that it is initialized before access. Dedicated accessor functions that check for and perform initialization can't completely solve this problem but at least give you a hook to solve it.The above two problems are with the implementation of global variables. The third problem is more with the concept of global state which is that global variables are basically by definition singletons. There are a lot of instances where "global" state turns out to not be global. GUI frameworks are notorious for this, treating the GUI handle and the event loop as global singletons. This is undeniably convenient as you avoid passing context objects around in every part of your code. It's particularly convenient in callback heavy code as it is one less but of context you have to figure out how to get back to your callback in a language with no native support for nested functions or closures. But embedded applications are not immune to this, often treating things like "the" serial/console port as a global. If a future implementation requires multiple IO devices can result in a lot of code that needs to be rewritten.So not evil but something you should think about, and there are good reasons why some environments heavily restrict them.

author: tggzzz
author_rank: Super Contributor
timestamp: October 22, 2022, 06:59:49 pm
content: Quote from: brucehoult on October 20, 2022, 10:57:26 pmThats complicated by the use of macros and pointers.While the former need not be a problem in well written C, the latter is a pain in the backside. Not for nothing are there "believe me because I am omniscient" compiler directives to discount the possibility of aliasing.Confession: I haven't used C professionally (except trivially) in a very long time. I can't even remember the outcome of the endless committee deliberations as to whether it should be possible or impossible for a cast to discard a const attribute (the "casting away constness" debate). There are good reasons for both options.

author: paulca
author_rank: Super Contributor
timestamp: October 22, 2022, 08:15:37 pm
content: As others have said it comes down to complexity, performance and footprint.As your applications expand global variables may start to become difficult to work with. By declaring them as global you are basically declaring them as "public free for all". You will have been using them here, there and everywhere and keeping track of them in your head. Have a few too many of them, or leave your project for a few weeks and come back and remembering how all those global variables interact might need you to re-read the whole code base again. If that's 1000 lines, fine. If it's 25 files and 10k lines, not so much.Maybe not mentioned, but extremely important. Team work. When you have more than one person working on a project the tendency is to protect each other from mistakes by not having random global variables which could be miss understood or used by two different programmers in two different places that the other is not aware of. That can lead to random bugs which will be a bear to find.So your code gets big and your team has a few members. You start writing wrappers around your data structures, putting some design patterns around them and your code size, memory size and performance all take a shift.As this grows and grows it gets exponential. At the top end, big enterprise code bases can be giga bytes in size with 100s of developers and lierally 99% of the code you write doesn't do anything, it's just structural framework and design patterns stacked on top of each other. Somewhere buried under it all will be a few lines of code that actually have a tangible electronic effect beyond the CPU. Like a socket.write. 99% of it is there to make the complexity manageable.This is why people have been desperately trying to get big enterprise out of creating monolithic applications and move to micro-services and other component pipeline or bus architectures, then you can write small independent services which on their own are simple, self contained and self protected "workers". They will even exist in their own little projects that can be given to junior engineers without giving them a panic attack or taking 3 weeks to set up the IDE for the monolithic application code.Obviously the hardware changes as you go up. Once you get into the land of x86 or ARM CPUs and Giga bytes of RAM the data structures you use become much more dynamic, much, much heavier on CPU and Memory but a lot more useful and flexible. No more managing delicate char buffers you will have "String" abstractions and Lists, Vectors, Maps, FIFOs, Queues etc. etc. Want to take a full 60 seconds waiting on a Wifi connection? That's fine, just make your UART buffer 10Mb. It will still be there when you come back.This is one of my personal procrastination points in MCU C... avoiding dynamic allocation and trying to juggle all the strings you have to deal with. It always seems either really, really clunky hacking through strings as arrays or really, really costly calling stdio and string.h functions.Your man Johnathon Blow mentioned that when Twitter started it had like 2 engineers and released a dozen features a year. Today it has nearly 2000 engineers and barely manages to release a single new feature a year! That's what exponential complexity does to projects.

author: tggzzz
author_rank: Super Contributor
timestamp: October 22, 2022, 08:31:09 pm
content: Quote from: paulca on October 22, 2022, 08:15:37 pmIt doesn't work out that way, of course. It is yet another cycle of the wheel. All that happens is that one form of complexity is removed, and replaced by another. And s/complexity/pain/, s/complexity/failure points/, etcHaving said that, the replacement system may be better (whatever that means). But usually that's merely because the whole lot has been dumped and replaced with something smaller that actually does what is required. Even that can be killed by an ignorant design authority stating the "new system must do what the old system does", i.e. implicitly including all the bugs that people have become used to living with.To bring it back to the topic of global variables, just because a system is distributed doesn't mean there is nothingequivalentto a global variable in an embedded application. All that's happened is that the scale has changed.

author: langwadt
author_rank: Super Contributor
timestamp: October 22, 2022, 08:46:31 pm
content: Quote from: tggzzz on October 22, 2022, 08:31:09 pmas usually the attempted solution to too much bureaucracy is more bureaucracy ...

author: peter-h
author_rank: Super Contributor
timestamp: October 22, 2022, 09:12:21 pm
content: I use globals a lot, where useful.But I always prefix them with g_ to make it obvious.And declare them, and their initial value (if any), in main.c, not all over the place.Globals, especially buffers, have many benefits compared to having them on the stack. One is deterministic (static) memory usage.

author: uer166
author_rank: Super Contributor
timestamp: October 23, 2022, 06:22:04 am
content: Quote from: peter-h on October 22, 2022, 09:12:21 pmYou don't need a global to put something into static memory. Astatickeyword within a function limits scope to that function and also keeps it off the stack. I think the argument here is largely to do with scope, not where the variable goes.

author: peter-h
author_rank: Super Contributor
timestamp: October 23, 2022, 07:02:42 am
content: True, declare "static" within a function. Although you then cannot find the address of it in the .map file; this may be development kit dependent. One can find the address by setting a breakpoint and seeing what it is.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 23, 2022, 10:20:11 am
content: Quote from: peter-h on October 23, 2022, 07:02:42 amand why do you care about where a variable is located?

author: peter-h
author_rank: Super Contributor
timestamp: October 23, 2022, 10:55:34 am
content: For debugging, to check whether it is 32 bit aligned, etc. Also not all memory regions are equally accessible e.g. on the STM 32F4, DMA cannot access CCM memory.

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 23, 2022, 11:15:33 am
content: If you just want to know the address, you can always declare a variable in a suitable ELF section recording the address. For example,Code:static uint32_t myvar;const uintptr_t address_of_myvar __attribute__((section ("addresses"))) = (uintptr_t)(&myvar);In your linker script, you can just drop the entire section, when not debugging. Otherwise, put it in Flash/ROM.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 23, 2022, 02:26:55 pm
content: if i want to check alignment or endianess i will just cast it (usually array) into some other datatype/union and watch its value, this applies even to dynamic allocated memory.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 23, 2022, 06:12:37 pm
content: Quote from: Jester on October 20, 2022, 05:47:08 pmInternet is an echo-chamber. People repeat and re-post what they see. Many of them work hard trying to put their pages on the top of Google searches. If something is everywhere, it does not necessarily have any merit.If you think the gloabal varibles are bad try to asses that- you can clearly explain to yourself why global variables are bad- you are able to write a program where global variables cause the problem- the problem is likely to occur in the particular program you're about to write- the danger of this problem actually occurring outweighs the benefits of using global variablesIf you affirmatively say "yes" to all of the four then you shouldn't use global variablesI wouldn't waste much time trying to follow different tips from the Internet, use your own judgment instead ... but wear tinfoil at all times.

author: newbrain
author_rank: Super Contributor
timestamp: October 23, 2022, 08:52:03 pm
content: Quote from: peter-h on October 23, 2022, 07:02:42 amMmmhh...From:Code:static const char *put_threads(bool first){static TCB task_id;...My ld.lld (clang linker) produced map file contains:Code:20009c4c 20009c4c 4 4 CMakeFiles/SDR1062.dir/source/gdbdebug/FreeRTOSdbg.c.obj:(.bss.put_threads.task_id)20009c4c 20009c4c 4 1 put_threads.task_idI'm using --ffunction-sections, so task_id above is in the bss section of put_threads.With gcc/ld, I also see them (this is an old map, I can't try right now to generate a new one):Code:.bss.y.10453 0x20000ba0 0x80 ./source/main.oFrom:Code:void TestTask(void *p){...for (;;){ulTaskNotifyTake(pdTRUE, portMAX_DELAY);GPIO_PortSet(LED_B_GPIO, LED_B_PORT, LED_B_PIN_MASK);static uint8_t y;...Here, the 10453 is added to make sure there are no conflicts with external linkage variables.Quote from: peter-h on October 23, 2022, 10:55:34 amIf the natural alignment is less than 32 bits, one of course cannot rely on it - any change in the code might affect it.The compiler takes care of that for you, if something special is needed you can instruct it (e.g. with _Alignas() in C11 and later).As for the various types of memory, the variable declaration itself plus the linker script should be enough to understand where it ends up (or the map file!)

author: paulca
author_rank: Super Contributor
timestamp: October 24, 2022, 11:11:52 am
content: Interesting points on the topic of hiding the fact variables are global. This generates a LOT of discussion and arguments in Enterprise space. For example, a standard technique in Java is just to have "public static" members of a class. As long as the class loader you are referencing has that class you can access that variable anywhere. OOP Priests will complain and whine and waste effort creating non-public singleton configuration frameworks (which, still at the end of the day accomplish the same thing) and in 6 months everyone will have started writing public static members again to avoid it! Having been the culprut of this at least a dozen times, my response was always, "I needed it done today. You are free to raise a tech debt Jira for it. Let's move on."Another approach is using some form of dependency injection such that all the classes keep all their stuff private and you let the framework inject them where they are needed.It's a paper cannon. You just inject the dependency into your code and effectively, it IS global. It's just the framework giving you the reference where ever you want it instead of you making it public yourself. It's the same thing just spelt different and the only meer improvement is that technically, you have a little more control. If you can stop other developers giving themselves control. It becomes a race between people giving themselves access to things and people trying to secure the code against the same engineers who are writing it. It wastes so much time, effort and money and barely achieves anything beyond making it all a little more complicated and costly.If you follow on down this route through Java you will start to encounter frameworks which practically write a whole new language on top of Java with almost every single member variable existing as an "implements Optional, Immutable" and insisting on making all state read-only and forcing you to use specific syntax and proceedures to modify state. Note that this WILL require a LOT of copy by value mechanics as actual (pointer) references are not sufficiently protected in Java. (Pedants: I mean literally return obj.cloneAsImmutable() type stuff.)I think it matters what you are doing in the code. Can a mistake (by machine or man) by undone easily? Is there a threat to life involved? I can see how a system modifying a critical value in a plane's air data computer must go through checks and balances and there has to be proceedures, such as multi-sensor elections, value averaging, limits, exceptions and so on and so forth. (relevant case of Toyota's ECU code causing some accidents, poor buggers had code analysists publish their static code analysis and tech debt lists in court).EDIT: I think the aim of protecting the code can either be it's criticality as above or maybe it's security. Usually it's not the intent to protect against mallace within the engineering team, but rather to protect against accidentally modifying something in a way you shouldn't. Protecting against accident, ignorance and possibly negligence. (or incompetence)The trouble is... people get interested in that stuff, start to learn it and in order to continue to learn it and prove it was worth learning they try and enforce it everywhere.Writing C for MCUs is a breath of fresh air when you see things like blind, bare, global functions and call backs already declared. Coming from enterprise world, this ironically almost seems like black magic voodoo, exactly as an MCU engineer would see something like JNDI dependency injection.EDIT: I noted that STM are currently under going a battle of similar lines in their HAL libraries. Lots of IFDEFs popping up removing the "legacy weak global callbacks" and making you registerCallbacks (inversion of control pattern). Welcome to my world

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 24, 2022, 11:28:41 am
content: Quote from: paulca on October 24, 2022, 11:11:52 amit is to control codes/modules/classescoupling, to easedebuggingandmaintainability. those concept are created by computing scientist, not a programmer somewhere at the backyard. yes it introduced bloatness and complexity into coding, but that to maintain some consistent protocol/channel on how to access things. we can argue about waste of processing power, but its not the problem to computer scientists, its the problem for engineers, processing power will keep growing, but the theory will remains and will be more and more relevant in time. this also we can assume it for near unlimited resources and processing power, ie on larger scale of software and hardware. as stated repeatedly, if your system is small and limited, its not for you. dont try to use a hydraulic jack to push a nail into the wood, thats certainly nonsensical.

author: Warhawk
author_rank: Frequent Contributor
timestamp: October 25, 2022, 09:45:36 am
content: I occasionally use global variables too. I don't think this is evil if you understand problems that globals may cause. From my experience, the worst codes to debug, maintain and understand, came from coders/programmers who were trying to do "everything right".I personally rather see a small, short, crisp and easy to understand code using global variables than a complex strict encapsulation on a small microcontroller.However, I am only a hobby coder and this is my opinion.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 25, 2022, 01:38:22 pm
content: Quote from: Mechatrommer on October 24, 2022, 11:28:41 amThe complexityisthe problem. A simpler program uses less resources, is less prone to bugs, is easier to write, to understand, and to maintain.One of old programmers said: "novices ignore complexity, professionals deal with complexity, geniuses remove complexity". I don't even know what to say about those who deliberately add complexity.

author: Warhawk
author_rank: Frequent Contributor
timestamp: October 25, 2022, 07:38:14 pm
content: Also one to the topichttp://www.ganssle.com/articles/globals.htm

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 25, 2022, 08:32:37 pm
content: Quote from: Warhawk on October 25, 2022, 07:38:14 pmthat article starts with strawman fallacy...

author: uer166
author_rank: Super Contributor
timestamp: October 25, 2022, 11:42:50 pm
content: Quote from: Mechatrommer on October 25, 2022, 08:32:37 pmSeriously.. what the hell are they smoking:QuoteThe same exact thing can be set by "OOP" trash with a thousands of getters and setters, the problem has nothing to do with globals per se.

author: Warhawk
author_rank: Frequent Contributor
timestamp: October 26, 2022, 07:45:50 am
content: You're never happy. This forum became one insult after another. I go for a walk.

author: tggzzz
author_rank: Super Contributor
timestamp: October 26, 2022, 07:54:16 am
content: Quote from: Warhawk on October 26, 2022, 07:45:50 amI don't see any insults in the preceding two messages.I do see something irrelevant and some poor reasoning. Such is life.Walks are good for clearing the brain

author: JPortici
author_rank: Super Contributor
timestamp: October 26, 2022, 08:06:12 am
content: Quote from: uer166 on October 25, 2022, 11:42:50 pmYou (should) know who the author is and how to weight his opinion.I stand with Warhawk, too many pissing contests lately

author: newbrain
author_rank: Super Contributor
timestamp: October 26, 2022, 09:11:20 am
content: Gannsle's article goes a bit for hyperbole, and for some counterfactual information (Ariane 5 was, in fact, lostbecauseranges were checked!).But I have seen and fought with legacy, globals galore, code. It's not fun or productive.Still, he makes good points on how to write robust code: limit the globals, write self-contained modules with clear interfaces, yadda yadda.Nothing really revolutionary, in my view.Just a sample: in one of my projects, about 200 kLOC, I have a half dozen of globals:They provide state to whole program.They can be read everywhere.They are written in exactly two points: user input, or loading of a saved preset.Given the above, I did not bother with accessors. Should the need arise of more writers, I might consider it.

author: brucehoult
author_rank: Super Contributor
timestamp: October 26, 2022, 09:32:12 am
content: Quote from: newbrain on October 26, 2022, 09:11:20 amNever check for any error condition that you don't know how to handle better than just ignoring it!Writingif (unexpected) trigger_self_destruct()is often not an improvement.

author: JPortici
author_rank: Super Contributor
timestamp: October 26, 2022, 10:09:15 am
content: Quote from: newbrain on October 26, 2022, 09:11:20 amTrue, nothing groundbreaking but it's worth being repeated to death. The importance of writing clear, understandable, clean code is lost on the majority of programmers. Limiting globals to enforce tidiness and discourage laziness is ultimately good.Quotesame situation.Quotebingo. Problem is when more than one person is touching the code.

author: paulca
author_rank: Super Contributor
timestamp: October 26, 2022, 10:11:07 am
content: Quote from: brucehoult on October 26, 2022, 09:32:12 amThere is worse than that.A-holes who put hard runtime asserts into their library code.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 26, 2022, 10:34:22 am
content: Somewhat tangential, but something to keep in mind whenever you see clouds of holy wars gathering...tl;dr viral "problems" go viral, in part, specifically because, the experts that know those problems areshite, and avoid them. Whichvoluntarily excludesthem from the conversation. Then there's no authoritative voice to guide conversation, and it ends up dividing into camps that are mutually "obviously right" in their answers. Which, while they might be "right" more or less, the truer answer is, "it's a stupid question" -- it should be reframed to one that makes sense. But then the answer will be obvious and uninteresting to talk about....Put another way: an aspect of critical thought is not just to 1. recognize experts on the topic, but 2. recognize their absence when it happens -- that is, even on topics that they are likely to have seen, and still have not participated in. Consider if there might be a reason for that. It could just be accidental of course, but it might be intentional.So, keep that in mind with respect to "controversial" topics like this. Fortunately, this thread, I think, has drawn a fair diversity of users here, but that might not be the case everywhere, especially where the quality of discourse (in the thread, or more broadly) has been poor, further shooing off experts.More directly: this topic, as most basically stated in the title, easily leads to divisive thinking. It is an issue with some nuance, but one must look deeper to appreciate those nuances, and the question can be phrased better (though in this case it may take knowledge of the situation and possible alternatives to know how better to phrase it; that happens sometimes...often?..).Which is kind of a side issue these days; ironically, despite the diversity and scale of the internet, it's increasingly hard to find resources on questions like this, other than on Stack for example, and as it's not a conversation platform, there may be less incentive for experts to contribute to mostly-correctly answered questions. Or they assume (erroneously) that a reader may be able to find / anticipate related issues that haven't been mentioned yet. Or that answers change over time (especially for software, as languages, apps and OSs get upgraded) but nothing brings topics to the front for further review until commented uponNot that the SNR is any better at places like here. For question-answers, I'd rather skip to the answers rather than sift through ten pages of fluff (or a hundred..). But on those topics where conversation is necessary, yeah.Tim

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 26, 2022, 11:20:48 am
content: Quote from: T3sl4co1l on October 26, 2022, 10:34:22 amditto! when i see this kind of riddle i will just skip it. when other FB newcomers will like to answer to show how clever high IQ they are. 9 = 90 is just plain stupid written by moron, period. it will be more acceptable if 9 --> 90 (read mapped). is like in the other thread discussing about a scope, someone came and said DS1054Z is a "sampling oscilloscope", it came down to terminology differences. but i dont think its relevant to this thread. this topic is about "why should i care about something that is none of my business?", my context is this, but the problem is not in my context, but i would like to ask anyway. so 2 schools came, imho both are right within their own context. because once upon a time we came from school #1 so we understand why they say its not a problem.

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 26, 2022, 12:17:50 pm
content: Quote from: T3sl4co1l on October 26, 2022, 10:34:22 amI prefer the term "wrong question", but only because there are lots of people who are afraid of asking questions because they fear being ridiculed or pointed out as stupid.Reason being, it is not stupid, per se, justwrong. Many times those asking the wrong question have to be explained how the question is wrong. Typical reasons in my experience are loaded questions (that cannot be answered) and incorrect premises or assumptions leading to the incorrect question being posed, and especially that in the logic chain of the current overall problem a previous question before this was answered incorrectly, making this entire question irrelevant and useless.Stupid is when after having been pointed that out, the person just repeats the same question. Then ridicule is appropriate; but not as the initial reaction.In physics, various terms are used from "nonsensical" (as in "irrational", "meaningless" or "without practical meaning") to "ill-posed" (extending thewell-posed problemconcept by Hadamard), because mathematics is only applied to describe the behaviour of systems, and if the initial problem/question is posed wrong, then the results can be horribly wrong. In particular, in most physics simulations, the very first thing a physicist does when they obtain a set of results, is to checkif it makes any sense.I wish English had a term with suitable connotations here, like "missensical" or "mis-asked", which would immediately tell the asker that one or more of the premises or axioms related to the question are incorrect/unsuitable/unphysical, making the question itself irrelevant, necessitating a step back in the chain of logic for the underlying problem at hand –– but without making the asker feel stupid. We all make mistakes, and everyone should always have a go at fixing their question at least once.Missingimportant details is a very easy error to make. Perhaps "erroneous question"? Or is that too pretentious?

author: RoGeorge
author_rank: Super Contributor
timestamp: October 26, 2022, 12:19:25 pm
content: Quote from: paulca on October 24, 2022, 11:11:52 amDoh, but I bet it does, especially on Enterprise!

author: langwadt
author_rank: Super Contributor
timestamp: October 26, 2022, 01:18:14 pm
content: Quote from: brucehoult on October 26, 2022, 09:32:12 amhttps://en.wikipedia.org/wiki/Battleshort

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 26, 2022, 02:04:32 pm
content: Quote from: Nominal Animal on October 26, 2022, 12:17:50 pmthere are stupid content creators only for hunting "likes/views", and there are stupid followers, who react to the first's video... the video creator above is the later. they dont ask question, they try to establish their point of view through wrong notations, leading to misconception and harm esp to kids just started going to school.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 26, 2022, 02:09:14 pm
content: Quote from: T3sl4co1l on October 26, 2022, 10:34:22 amNothing wrong with that. Just fill in the missing bits in your mind. The answer is 12.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 26, 2022, 02:19:43 pm
content: Quote from: Mechatrommer on October 26, 2022, 02:04:32 pmIf you can't beat them join them

author: MK14
author_rank: Super Contributor
timestamp: October 26, 2022, 02:26:57 pm
content: Quote from: Nominal Animal on October 26, 2022, 12:17:50 pmI'd suggest, a suitable English term might be ...Ambiguous or Ambiguous question.E.g. What is 1 + ! = ?The answer could be 2, because I typed '!' instead of '1', or it could be an entirely different question. Hence it is AMBIGUOUS, because you can't tell readily/easily from the question, what the right answer is (without extra information, knowledge or help, from the question source).I.e. The question is (possibly) malformed (e.g. a typing mistake, or issue with the fonts, so it was suppose to be a '1', but came out as a '!', somehow).

author: timenutgoblin
author_rank: Regular Contributor
timestamp: October 26, 2022, 02:32:02 pm
content: Quote from: T3sl4co1l on October 26, 2022, 10:34:22 amQuote from: Mechatrommer on October 26, 2022, 11:20:48 amQuote from: pcprogrammer on October 26, 2022, 02:09:14 pm

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 26, 2022, 02:32:46 pm
content: Quote from: MK14 on October 26, 2022, 02:26:57 pmAnd then the answer would be 11(See the video Mechatrommer posted)

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 26, 2022, 04:12:55 pm
content: Quote from: Mechatrommer on October 26, 2022, 02:04:32 pmI consider those more like "lies and fallacies masquerading as questions", myself.I don't like even those called "stupid questions", because as I said, it makes those who just don't know the differenceyetafraid of asking questions –– and that means they never learn to ask good questions. And the world becomes less, if we do not ask good questions.Quote from: MK14 on October 26, 2022, 02:26:57 pmHmm... ambiguous: open to multiple interpretations. That's not it, because the point is that the question itself is incorrect, not that it can be interpreted incorrectly. In face-to-face, I can often infer the correct interpretation of ambiguous questions –– like "When you were carrying that TV yesterday, did you notice the friendly squirrel at front? Did you bring it inside okay?" typically "it" referring to the TV, and not to the squirrel. In written text, it is similarly common for the exact interpretation to be inferrable from the surrounding context, oftensubsequenttext, leaving the interpretation in a Schrödinger state for a paragraph or two.To be clear, I'm referring to questions like "Why isn't there any solutions tox*x - 2.0 = 0?", when the asker is really asking why their C code using thefloattype (float x = sqrtf(2.0f); float y = x*x - 2; if (y == 0) printf("Okay!\n"); else printf("Fail!\n");) fails. I indeed do occasionally answer this kind of questions, often with a snarky initial bite to get the OP out of the passive funk (indicated by the, uh, "inane" question they posed?), followed with actual useful help.And also questions like "I want to fix this engine using these two q-tips and a crow feather", or their programming or engineering or electronics equivalent. These are super-constrained so that no realistic solution is possible, unless you start by "First, trade one of the q-tips for at least two rubber strings no less than four inches in diameter", and describe the next thousand or so steps in detail.(And yes, I kinda like "inane question" even better than "wrong question", because its dictionary definition fits like a finger in a nostril. It's just that I don't see it used in everyday speech, so I think it might be perceived a bit snotty.)

author: MK14
author_rank: Super Contributor
timestamp: October 26, 2022, 04:51:37 pm
content: Quote from: pcprogrammer on October 26, 2022, 02:32:46 pmOne solution (to that video you mentioned), would be to say to the, possibly problematic pupil, towards the beginning of the video. You have won a big prize, with 22 nice sweets in it. The only catch, is you have to give just 2 sweets, to another pupil, and another two sweets, to a different pupil.How many sweets, do I remove from the prize bag, for the other pupils?4 or 22 sweets?

author: MK14
author_rank: Super Contributor
timestamp: October 26, 2022, 05:11:44 pm
content: Quote from: Nominal Animal on October 26, 2022, 04:12:55 pmBut you don't know if the question is incorrect or not (with absolute 100% certainty), that in itself, maybe a considerably harder question/problem to solve. Hence the term ambiguous.An expert on C, on this forum, may take one look at it, and say something like, "Since version xyz.123...... of the C standard, that (hypothetical, no connection to the C code you just mentioned) expression is always defined as ...".Or later in the job interview, they might say, that the question was purposely created to have no definitive exact answers. In order to make sure the possible future employee, is confident enough to simply say "They don't know the answer", or the question is ambiguous or badly formed (incorrect question).It might be that (the reader of the question), missed some additional information/clues. Which made the question answerable. E.g. A schematic, which says all resistors are 1%, 0.25watt metal film, unless stated otherwise.In other words, MAYBE the question is faulty, but it could also be that the reader (of the question), is simply mistaken or lacking experience, which would make the question unambiguous to them. So simply saying the question is incorrect, is NOT that simple.So I still think the term, ambiguous, is probably best.Real Life Example (from memory, so might be wrong, also I can't 100% remember the original question, so I may have changed it a fair bit).There was an online electronics test quiz, with (at the time it was written), perfectly valid questions. But it said something like:"How many transistors, might there be on a high complexity integrated circuit?".A:..10,000B:..1 millionC:..None of these answersNowadays, the correct answer is probably C, but at the time the question was created, answer B, or even A, could be correct. So I actually gave the wrong (as regards current technology) answer, in the hope it was the correct answer for when the online quiz question was created.EDIT: On reflection, you could always say "Incorrect Question", I can't really object.

author: AVI-crak
author_rank: Regular Contributor
timestamp: October 26, 2022, 11:42:36 pm
content: Quote from: Jester on October 20, 2022, 05:47:08 pmHint, a global variable should be declared like this:Code:register volatile uint32_t __very_important_5214 asm ("r7");

author: brucehoult
author_rank: Super Contributor
timestamp: October 27, 2022, 12:01:06 am
content: Quote from: AVI-crak on October 26, 2022, 11:42:36 pmI've done that a few times, but I think I used r9.Works very nicely, even calling out to libraries that don't see this declaration (e.g. 3rd party) -- as long as you don't have any callback functions passed to them (including virtual functions in your own derived classes).

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 27, 2022, 01:19:35 am
content: It compiles, so it works.TM

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 27, 2022, 08:04:12 am
content: Quote from: SiliconWizard on October 27, 2022, 01:19:35 amYou monster!

author: tggzzz
author_rank: Super Contributor
timestamp: October 27, 2022, 09:01:56 am
content: Quote from: SiliconWizard on October 27, 2022, 01:19:35 amThe modern variant of that is "it passes the unit tests, so it works".Regrettably I couldn't trademark that because it is common usage

author: langwadt
author_rank: Super Contributor
timestamp: October 27, 2022, 09:20:19 am
content: Quote from: tggzzz on October 27, 2022, 09:01:56 amso it worksso it ships

author: paulca
author_rank: Super Contributor
timestamp: October 27, 2022, 09:56:54 am
content: Quote from: SiliconWizard on October 27, 2022, 01:19:35 amThe number of times in work you will here me say, "Just run it! Stop checking it, run it and you'll find out if it works." LOL

author: paulca
author_rank: Super Contributor
timestamp: October 27, 2022, 10:01:04 am
content: On the debate. I find this forum awesome because there are so many, very, very smart people in here. From a wide range of backgrounds and views.The original topic was just the cat thrown to the pigeons.It went how I would have expected it to... if the OP wanted an actual answer, then I don't think this would be the place to ask. I for one wasn't taking it seriously, just a water cooler heated debate we will all just walk away from back to our benchs and desks and mummble about for a while.My own opinions in this were delibrately biased against complexity, however I'll be the first to introduce standards, conventions and best practices in a project in work. IF they are necessary.The only negative that drags it down is when the attacks turn from the ideas to the people who proposed them. If you find yourself using "you" in the none 2nd sense and are indeed directing "you" to an individual and not the idea. I would suggest you stop and consider it rude. Ideas are stupid, it doesn't mean the person with that idea is stupid. Consider the gold fish thought experiments.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 27, 2022, 10:53:35 am
content: Quote from: paulca on October 27, 2022, 09:56:54 amalmost everytime immediately you will know it works... what you are going to find out sooner or later is if it doesnt work... and worse when you already send the project to the moon. so i guess more precise word is... "run it and you'll find out if it doesnt work"... hint: semantic error...

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 27, 2022, 10:58:29 am
content: One useful approach to use and avoidance of global variables is to consider applications and the conflict betweensingle or multiple documents per process.It is useful to group the state variables in an application between "application state" (application configuration, like which windows are shown and where, what language is the user interface, and so on) and "document state" (document or current task configuration, like say page size, content language, and so on).If you write an application that creates a new process for each document opened, then you can keep document state in global variables just like application state. However, each instance is separate, so if you e.g. change the user interface language in one, other open instances are not affected.(Note that you do not actually waste memory doing this in current operating systems, because they use virtual memory, and directly map libraries and executables to memory. Each process has their own stack and kernel metadata, and of course any read-write data memory segments/sections/areas, but there is only one copy of the read-only code segments in memory.)If you write an application that can handle multiple documents at once, you have "application state" (configuration) and "document state" (document settings). While "application state" is global to the entire process, the "document state" is specific to each document, and you must not keep any document state in global variables. If the user starts a new copy of the application while one is running, instead of running normally, the new instance just sends an event or file open request or new document request to the already running application, and then exits.Now, extend that idea to a library, or even to a facility in your own program or microcontroller hardware.If there cannot be more than one instance because of physical limitations, then global state is fine. However, often it is more useful to be able to create multiple instances of the thing/facility; and then you cannot use global state.Here is a practical example. I love to use the Xorshift64* pseudo-random number generator, because it is extremely fast, and because if one uses only the 32 high bits of the result, it passes all randomness test in the BigCrush randomness test suite:Code:#include <stdint.h>/* Xorshift64* PRNG state.To randomize the sequence, initialize to any nonzero value.*/static uint64_t prng_state = 1;static inline uint32_t prng_u32(void){uint64_t x = prng_state;x ^= x >> 12;x ^= x << 25;x ^= x >> 27;prng_state = x;return (x * UINT64_C(2685821657736338717)) >> 32;}I left out the randomizing function, because I like to use the Linux-specificgetrandom()call for it, but one could also use POSIXclock_gettime()or even the C89time()or BSDgettimeofday()for time-based initialization.The above works, is very fast and very random (assuming you choose a random initial 64-bit seed,prng_state, as otherwise it obviously produces always the same sequence).However, you only have one generator per process.Let's say you have a multithreaded process, but you still need repeatable results (based on seeds for each thread or task at hand), so you cannot use one global pseudorandom number generator. What to do?Well, make it non-global, of course. The first step:Code:typedef struct {uint64_t state;} prng;#define PRNG_INIT(seed) { .state = (seed) }/* void prng_randomize(prng *g); -- omitted, because it tends to be OS-specific */void prng_init(prng *g, uint64_t seed){if (g) {/* Note: zero seed is not allowed, so we replace that with 1. */g->state = seed | !seed;}}uint32_t prng_u32(prng *g){if (g) {uint64_t x = g->state;x ^= x >> 12;x ^= x << 25;x ^= x >> 27;g->state = x;return (x * UINT64_C(2685821657736338717)) >> 32;} else {return 0;}}This way, in your own code, you just declare a random number generator you want to use, and initialize it to the desired seed,prng mine = PRNG_INIT(1); /* Seeded with 1 */or equivalentlyprng mine;prng_init(&mine, 1);or randomized viaprng mine;prng_randomize(&mine);and then generate the pseudorandom sequence usingprng_u32(&mine)calls.(It is straightforward to extend such a state structure to contain both the needed state, as well as a pointer to the generator function, so that one can choose the PRNG implementationat run time. Since the high 32 bits of Xorshift64* beats even Mersenne Twister in randomness, I don't bother anymore, though.)See how the concept of "state" generalizes? It is quite intuitive, and functional approach to global variables.A counterexample, and a common one seen in Arduino sketches:Code:int i;void foo(void){/* ... */for (i = 0; i < 5; i++) {/* ... */bar();}}void bar(){/* ... */for (i = 0; i < 15; i++) {baz();}/* ... */}The bug is obvious: whenever we callbar()from within the loop infoo(), the loop index variable gets modified, and thus the code does something completely different than what a straightforward reading of the code would indicate. In this case,foo()will only callbar()once.The key is to think aboutwhythis is a bug. We've erroneously globalized the internal state offoo(), which then gets unexpectedly modified by a call tofoo().Apologies for the wall of text, but hopefully it was worth reading.

author: Siwastaja
author_rank: Super Contributor
timestamp: October 27, 2022, 12:57:22 pm
content: Keep state as local as possible is a good general advice not limited to globals vs. locals.I hate to see C code where all local variables are defined at the start of the function; especially if it's a bunch of loop variables, temporary variables of different types, etc. Even the older C standards allowed definition at the start of ablock, and for a long time, variables can be defined in the middle of block (and inside the for loop initializer, for(int i = 0; ...))This not only limits the scope of the variables, actually preventing bugs (because using the name elsewhere now just results in a compiler error about undefined name), but also makes code much more readable as you don't need to scroll far to find what is going on.The same is about keeping static state. At least I went through the learning stages: first I just used global variables to keep state. Next I learned they don't need to be exposed globally, make them static. Later I realized I can put them inside function, if the use is limited to one function, limiting the scope to this function only. And last, I realized it doesn't need to be at the start of the function. Consider the differences in readability:Code:int uart_initialized = 0;void initialize_uart(){... do things ...if(!uart_initialized){... things ...uart_initialized = 1;}... things ...}Code:void initialize_uart(){static int uart_initialized = 0;... do things ...if(!uart_initialized){... things ...uart_initialized = 1;}... things ...}Code:void initialize_uart(){... do things ...static int uart_initialized = 0;if(!uart_initialized){... things ...uart_initialized = 1;}... things ...}Code:void initialize_uart(){... do things ...// you can even limit the scope further!{static int uart_initialized = 0;if(!uart_initialized){... things ...uart_initialized = 1;}}... things ...}

author: Buriedcode
author_rank: Super Contributor
timestamp: October 27, 2022, 05:41:51 pm
content: Quote from: brucehoult on October 20, 2022, 10:57:26 pmI just wanted to double the visibility of this and highlight the pointHaving worked on 8-bit MCUs with 1k program space, and at the other extreme on a team working on a large multi OS app, certain "rules" simply cannot be applied equally to both ends of that spectrum.I suppose habits that are completely device/code/compiler independant such as variable naming conventions can cover almost every area, but as soon as it relates to architecture the differences are so great the number of sweeping generalisations diminishes.

author: coppice
author_rank: Super Contributor
timestamp: October 27, 2022, 05:49:53 pm
content: Quote from: Buriedcode on October 27, 2022, 05:41:51 pmOh, the same rules can be applied, and often are. Someone used to big software tries writing for a small MCU, fails to adapt and concludes the application just cannot fit. The project is cancelled. If someone more flexible later picks up the problem a product may be produced.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 27, 2022, 06:07:28 pm
content: Quote from: Siwastaja on October 27, 2022, 12:57:22 pmYou have to. But not all people know this. It is very easy for to put a variable into a .c file (as opposed to .h) and think that it is now hidden from the outside. And it is, sort of, true - the compiler which compiles other .c files doesn't see it. But the linker does. So, if someone has two .c files with a variable named "counter", the linker will map both to the same memory space, creating complete mess. To prevent this, you must use "static".This confusion happens because for the compiler there's no difference whether something is in the .h file or .c file. The compiler doesn't know which part of the code is going to be exposed to other compilation units through the .h file, and which part is not. Hence, the rules for both .h and .c files cannot be different. If you put a variable into the .c file, the result is the same as if it was in the .h file. In contrast, pascal has two different sections - "interface" for exposed variables and "implementation" for anything local to the compilation unit. In C you must use "static".If someone forgets "static" for a file-scope variable it will become gloabal for the linker. But this is unintentional. This doesn't affect the use of global variable when you really meant them to be gloabal.

author: uer166
author_rank: Super Contributor
timestamp: October 27, 2022, 07:42:16 pm
content: Quote from: Siwastaja on October 27, 2022, 12:57:22 pmYou can go even further and say that state as a general concept is the root cause of a lot of complexity and some % of hard to reproduce bugs. I think in certain cases it's actually agoodthing to centralize state (whether you make it all global or not), such that the system is easily observable, and all state is accounted for. Just imagine some power converter with a few control loops that use global V/I/PID state/Lead-lag state variables, but where each function is entirely state-less on its' own. To me that's a perfectly valid solution that doesn't bury scope of state to the point that it's hidden.Idk why I'm still rambling on this other than to show that nothing a fit-for-all advice, and appeal to authority is not really a valid defense of any argument. Reducing total state space of a running program is a much more agreeable concept to most though, compared to globals vs. locals vs. shit and sticks.