Where is Your Data?
Tags: c, cpp
Published: 2020-09-18 01:52:20

## Introduction
Making source code easier to read without significantly increasing its size is always a win. For **C** and **C++** I've developed a simple convention to make clear the distinction between data residing in one of two types of static data segments, data which resides on the stack, and the visibility of static data (global or single source file). This is very useful when writing multi-threaded apps.

## Possible Data Locations
In terms of where data can exist within a given process space, there are only four locations:
1. Static data segment
2. Thread specific static data segment
3. Heap
4. Stack

That's it. Really. If you are writing a multi-threaded application, it is **vitally** important that you know the location of all data. No amount of OOP wizardry can defer for very long your need to know this. It is to your advantage to leverage each of these locations for appropriate purposes.

## Globally Visible Static Data
Despite what programming language ideologues may say about the evils of global static data, I find some is usually necessary when writing non-trivial applications. Also, I've found it useful in my source code to make clear whenever global data is involved. Here is how I do this, usually in a file named: _"NameOfProject.h"_
```
struct Global {
   int nClients; // or whatever
   /* and so on */
};
extern struct Global G;
```
Now when I need to do something with _nClients_, it must appear prefixed with 'G.'
```
printf("Client count is: %d\n", G.nClients);
```
You will of course need to instance 'G' in a _.c_ or _.cc_ file somewhere.

## Single Sourcefile Static Data
In **C** and **C++**, (outside of any class declarations) the "static" keyword is overloaded; in the context of data instances, it means that the data will be located in the static data segment, **and** that the symbol will not be visible in the corresponding object file for the purpose of linking; which is to say that the symbol is _invisible_ to other source files. This is a lot simpler than other mechanisms for scoping static data, and it works in both **C** and **C++**. You will need to place code similar to this in your _.c_ or _.cc_ file:
```
static struct {
   /* Correction specifies _Atomic.
    * Thanks Andrew Clayton for pointing out
    * this omission!
    */
   _Atomic int n_someFuncCalled;
   /* Other stuff */
} S;

int someFunc()
{
   ++S.n_someFuncCalled;
   /* Works no matter how many threads */
   return 0;
}
```
Here the source file scoped data which resides in the static data segment is prefixed with 'S.'.
Likewise, for thread-specific static data you can do this:
```
static _Thread_local struct {
   int n_someFuncCalled;
   /* count is only for the current thread */
} TS;
```
Accessing this data requires the prefix 'TS.' Data found in _TS_ resides in the static data segment which is unique for each thread.
## Reduce Function Argument Counts
One advantage of using the static data segments is reducing the number of arguments you must pass to some functions. This can, of course, be exploited to write sloppy and unmaintainable code. On the other hand, with proper understanding it can be used to write more robust and efficient code.

## Conclusion
I cannot overstate the importance of knowing where your data resides in a multi-threaded process. This article presents a simple and practical way to represent this in source code. If you'd like to see an example of a real project using this technique, please have a look at [ban2fail](https://github.com/jrbrtsn/ban2fail)
Happy coding!