Preprocessor magic: Designated Initializers in C Function Calling
Inspired by the discussion in the comments of the previous post on using default argument in C using the preprocessor, I am going to write about using the C99 designated initializers feature on functions rather than just simply in an initializer list of a structure.
But first of all let's see what a designated initializer list actually is. It is a feature introduced in the 1999 revision of the C standard. It currently is not a part of the C++ standard so you can't use it in C++, but only in C. Of course in C++ you can just make a C file, include it in your project and do anything you want with designated initializer lists in there. Then in the point where you include the C-specific code just do :
#ifdef __cplusplus extern "C" {///opening bracket for calling from C++ #endif ... C code ... #ifdef __cplusplus extern "C" }///closing bracket for calling from C++
So what is a designated initializer list? It is something that enables you to give values to specific (designated) parameters of a struct using an initializer list. Refer to the following code for an example.
// a structure with some parameters typedef struct a_struct { int param1; int param2; int param3; }a_struct; // using a normal initializer list a_struct a1 = {10,20,30}; // using a designated initializer list a_struct a2 = {.param3 = 30, .param1 = 10};
As we can see, in contrast to the normal initializer list, you can use the syntax of <.variableName = value> inside an initializer list to provide values of only specific parameters of a struct in any order you desire.To see more information about designated initializer lists and also the limitations of their use read the C99 standard, Section 6.7.8, page 125.
So having established what we are dealing with let's define a structure in a header file (say foo_header.h) that will be the main subject of our experiment which we will call foo. The first 4 members are going to be used during construction and the others are in there just to show that foo can have more member parameters than the first four. Then just like in the previous post we shall define another structure which will only be representing the arguments given to initializing foo and we shall name that structure as foo_arguments. Then we declare three functions which are:
- i_foo_init():To normally initialize a foo struct
- i_foo_init_arg():To initialize a foo struct using the compound literals method introduced in the previous post
- foo_init(): This is the macro that we will be using to actually initialize foo with designated initializers
// Defining the default values of the variables #define V1_DEFAULT 2006 #define V2_DEFAULT 0.659 #define V3_DEFAULT 'A' #define V4_DEFAULT "I am a default value" typedef struct foo { //These are the foo members that are typically initialized during construction int var1; float var2; char var3; char* var4; //these are members used by foo and not initialized during construction int otherData1; char* otherData2; }foo; //We create a struct to hold the initializing parameters of foo typedef struct foo_arguments { int var1; float var2; char var3; char* var4; }foo_arguments; // The normal foo initializer foo* i_foo_init(int v1,float v2,char v3,const char* v4); // The variable argument initializing function for foo foo* i_foo_init_arg(foo_arguments args); // This is the function that will be initializing foo #define foo_init(...) i_foo_init_arg( (foo_arguments) {__VA_ARGS__} )
Now in a corresponding source file (foo_source.c) we will input the definition of the functions.
#include "foo_header.h" // The normal foo initializer foo* i_foo_init(int v1,float v2,char v3,const char* v4) { foo* ret = malloc(sizeof(foo)); ret->var1 = v1; ret->var2 = v2; ret->var3 = v3; ret->var4 = v4; return ret; } // The variable argument initializing function for foo foo* i_foo_init_arg(foo_arguments args) { int v1; float v2; char v3; char* v4; v1 = (args.var1 !=0)? args.var1 : V1_DEFAULT; v2 = (args.var2 !=0)? args.var2 : V2_DEFAULT; v3 = (args.var3 !=0)? args.var3 : V3_DEFAULT; v4 = (args.var4 !=0)? args.var4 : V4_DEFAULT; return i_foo_init(v1,v2,v3); }
Now what does the above do? If you read my previous post you would know, but let me re-iterate for those who did not. i_foo_init() is your standard initializing function. Takes in the values of the parameters and returns the initialized structure. On the other hand i_foo_init_arg() takes in a foo argument list and reads its members in order to initialize a foo function. If a member parameter is set, then its value is given to the initialized foo, if not then the default value is given to foo. But why go through this extra layer of initialization? What do we gain?
Well the answer lies in the definition of the actual initialization macro (copied below for your convenience). Notice that the variable arguments are put inside an initializer list but with the "cast" in front we obtain a compound literal statement. This means that the arguments given to foo_init() are turned into a foo_arguments structure and then passed to our i_foo_init_arg() function.
#define foo_init(...) i_foo_init_arg( (foo_arguments) {__VA_ARGS__} )And this is where the magic happens. Let's say that we are inside the main function now. We can now use designated initializers with foo_init() even though it is a function. Why? Because of the extra initialization level at i_foo_init_arg where we are turning the arguments into an initializer list, hence turning them into a structure which itself can accept designated initializers. For examples look below
int main() { //initializing only the last 2 parameters foo* f1 = foo_init( .var3 = 'c' , .var4 = "I am given by a designated initializer list"); //no value given, all values are default foo* f2 = foo_init(); //initializing all the parameters in a screwed up order foo* f3 = foo_init(.var4 = "Hello", .var2 = 2.71828, .var1 = 100, .var3 = 'Z'); //initializing only one argument and the rest are default foo* f4 = foo_init(.var2 = 3.14159); //--the big limitation of this method-- (Gets initialized with default values since 0 gets interpreted as no value given foo* f5 = foo_init(.var1 = 0, .var2 =0, .var3 = 0, .var4 = 0); return 0; }
We can see from the examples above that we can initialize any argument we want and in any order. That's pretty awesome and can come in handy in many situations in an actual program. On the downside as also stated in the previous preprocessor post we can't give 0 as the value of an argument since this is the way we detect if no value has been given. Look at the initialization of f5 for example. One would expect to see it full of 0s but instead, foo f5 is initialized with all the default values. Why? Because when the initialization gets inside i_foo_init_arg() it detects the 0s and substitutes them with the default value. So this method is pretty nifty as long as you realize the danger of using 0s for initialization and avoid them.
So in conclusion in this post we saw a way to utilize designated initializer lists in function parameters instead of just the usual way of initializing structures. It is a pretty nice method in my opinion and can offer really concrete advantages to the programmer by making his code a lot more readable and easy to write. At the same time there is the problem of passing 0 as a value of an argument which has to be kept in mind if one uses this method. If you have any comments, found some mistakes in my code above or want to discuss the method presented please leave a comment. All feedback is appreciated and helps in improving. Also if you liked this post I would suggest you follow me on Twitter for more updates, comments and rants on programming and stuff in general. Thanks for reading!
Productivity Tips and Going into “The Zone”
Productivity is a matter of major concern for people in all walks of life but I would like to talk a little about productivity for software developers. Writing code for any software project is not an easy task. Productivity tends to differ by the day, even by the time period inside a single day of work. In this post I would like to gather some things that have proved helpful to me in order to increase productivity in case anyone else might be looking for ways to do so.
For programmers the point of utmost productivity is often described as "The Zone". The point where you basically just create automatically without much thinking. Different people describe it with different words. I would say that "The Zone" is when the code is perfectly clear in your mind and is just writing itself on the screen. So here we go, my tips on how to achieve that.
- Sleep
I can't stress this enough. No really I can't. Many people, myself in the past included, seem to believe that staying up awake, squeezing yourself for these last few lines of code will help, that it will finish the project faster. The reality of it is that depriving yourself of sleep, even if it is one less hour of sleep every day, you are also depriving yourself of clarity of mind. That brings a lot of other trouble work aside, such as loss of energy to go about your daily life. As far as programming is concerned it introduces bugs. No matter how sure you might be of adding that function or of altering that class the fact of the matter is that there is a big chance of introducing bugs due to not being careful enough.
Not to mention that this is a vicious cycle. Mess up you sleeping schedule one night and it will probably haunt you and your code for days if not weeks. I have not managed to go into "the Zone" when I was sleepy and needed to work. There is a reason for that. It is a mode of utter concentration. Who can concentrate when his body is crying for sleep?
- Isolation
When you work, you work. That's it. Isolation from everything. Chatty co-workers, facebook/twitter, mom/dad, generally anyone that might be around should be ignored totally when working. You can't concentrate on anything if every 5 minutes someone comes by attempting to start a conversation online or in the real world. Don't get me wrong, I don't urge people to be anti-social but there is time for socializing and time for working. Choose your time appropriately but once that has been done stick to it. If people attempt to bother you, politely reject any invitations and keep on working. Put up a sign to deter people from bothering you if need be.
- Motivation
People often overlook the effect that motivation has on productivity. If you are passionate about the project you are working on, and have enough motivation to keep working on it, you will be productive. It's that simple. So if the project is your idea, a start-up perhaps, then the odds are with you. If on the other hand this is a project in your workplace that you have assigned to a team of programmers then providing them motivation is a key to success. Possible motivation for coding at a workplace would be to actually evolve one's skills through their work even if they are not that excited about the project in itself.
- Exercise
I know that programmers, computer guys and geeks in general are infamous for their lack of exercise but the fact of the matter is that it is needed. As the ancient Greeks used to say "Healthy mind in a healthy body". Exercising will keep you fit and healthy and can take your mind off your work. This is needed and it is needed on a daily basis. How many times have you pondered over a really tricky piece of code in vain only to go away from the code, clear your head for a while and then come back and see the mistake clear as day? Stepping back from the computer and the code is a necessary thing that you have to do as a programmer every so often and what better way to do that, than going to exercise? Exercise will keep you healthy, satisfied with yourself and also produce endorphins often associated with general feeling of happiness. Happy programmer often results into good code.
- Comfortable workspace
A programmer's workspace should be comfortable. Being comfortable will promote productivity and keep all distractions from the task at hand to a minimum. A workspace consists of many objects that can affect comfort. These are the desk, the distance of the keyboard/mouse from you and the chair. Also good ventilation of the space one works can boost performance. In my opinion the most important from the above is the chair. A good chair does a world of difference.
Workspace setup does not only affect comfort and productivity but also your very health. Improper/long-hour usage of the mouse and keyboard can lead to Repetitive Strain Inury (RSI). Also not sitting properly in the chair either consciously or just because it's a bad chair, can lead to serious back injury in the long run. Here are some nice tips on how to set up a proper computer workspace.
- Music
This is a personal favorite. Not everyone would agree but for me listening to music with headphones helps to shut the world off and concentrate. Music soothes and helps to focus. Listening to the right kind of music while working can give a very big boost and often contributes to going into "The Zone". Actually for me different kind of music suits working on a different time of day. Refer to the (extremely) rough graph below. In it is my personal estimation for productivity during a typical day. 8 does not need to represent 8 in the morning, just the hour you wake up and 24 the hour you fall asleep.
What I want to show with this is that rhythm can help with one's work. One would normally listen to nice melodic music (depending on one's tastes) to provide good rhythm for the work during the day and to help shut off any disturbing noises. On the other hand when the hour to sleep is approaching and fatigue starts to get to you that's when energetic music should come in to provide that so much needed boost. I myself tend to be more productive during the last hours before sleep as can be seen in the graph, since this is when I have the least amount of disturbances but that would differ per person I suppose.
So that was it. These are the factors that I believe mostly affect productivity for a programmer. If anyone has some additional suggestions please mention them in the comments below. I would be really interested to hear the opinions of fellow coders.
