Iris Classon
Iris Classon - In Love with Code

Stupid Question 52: What are preprocessor directives? (In c#)

[To celebrate my first year of programming I will ask a ‘stupid’ questions daily on my blog for a year, to make sure I learn at least 365 new things during my second year as a developer]

What are preprocessor directives?

Another fancy word! During a region discussion earlier this year I came across something that looked like regions, preprocessor directives. Wow. Fancy words. Let’s try that again Pre-Processor-Directives. What is that? Well, regions are preprocessor directives if I’ve understood MSDN correctly, but they don’t do much - it’s more of an editor feature that sure sparked some debate on my blog a few days ago (37 comments so far :D!! ).

So what are preprocessor directives? I had to look this up, as I wasn’t quite sure, not 100%. (And please forgive my VERY simplified and short answer, it’s late, I’ve been working for 14 h non-stop and I am dead tired. I’ll work a bit more on this blog post later this week)

SO you have your code, the source code. When you compile and run that code you get your program (hopefully) up and running. So it’s the puzzle that pieces together your program. If you would like to treat some pieces of that puzzle differently by the compilator you can use preprocessor directives to tell the compiler how to treat that part of the code. For example, you might want to skip something during debug and debug only etc. Basically you have these ones to work with:

#if
#else
#elif
#endif
#define
#undef
#warning
#error
#line
#region
#endregion

Example from MSDN:

#define DEBUG
// …
#if DEBUG
Console.WriteLine(“Debug version”);
#endif

Pretty neat stuff I reckon! Have you used preprocessor directives? And what would be some great usage scenarios? I know my answer is very simplified, I tried to come up with a great explanation for how it works behind the scenes, but I got a tiny bit confused - and then I ran out of time and had to go to bed :) Would love some more info about that, so please share if you have some great links!

Comments

Leave a comment below, or by email.
Roman Mueller
9/25/2012 2:29:01 PM
Unfortunately I also don't have a link, but some historic information (just what pops into my mind).
the preprocessors have been around for a long time. The first time I personally saw them was in the early 90s working with C, later C++.

They basically help you controlling which parts of your code are going to be compiled. Maybe you could call it conditional compilation of your code. Often used to share code amongst platforms with small differences in code required.

Hope I didn't confuse more than explain ;) 
Dima
9/25/2012 2:31:23 PM
Hello, Iris) As I know, probably, the most used scenario is so-called "conditional compilation". For example, at my previous job, we had some third-party component, which most of the team didn't work with, and so, parts of code that use that component were under some #if use_component and so on. So, the most of the developers could build the project without that component. It is useful sometimes, but, as for me, there are also some great problems with that. With all these conditions a lot of chaos could be created, when you are not able to see clearly, what parts of code will be compiled now and what will be excluded. So, I would be very careful with that.
For the alternative Debug scenario, I think, you could check these articles: Conditional Methods Tutorial, The Conditional attribute.
Good luck! 
Dave Transom
9/25/2012 3:07:31 PM
They're actually quite useful in a variety of ways.

You can output #warnings during compilation to the IDE output window (and the  IDE Error List) e.g:
#warning You've done something really hacky here!

Or consider throwing a not implemented exception at runtime. Well the equivalent at compile time (which will halt compilation) would be:
#if !MY_SYMBOL
#error Compilation outside of debug
#endif

Then there is ignoring warnings that you are aware of (and want to ignore in an attempt to get to 0 warnings by fixing those you can, and accepting those you can't)
#pragma warning disable 414, 3021
[CLSCompliant(false)]
public class C
{
   ...
}
#pragma warning restore 3021
[CLSCompliant(false)]  // CS3021
public class D
{
   ...
}


A list of warnings codes can be found here: http://msdn.microsoft.com/en-us/library/ms228296%28v=VS.90%29.aspx


I use #if #else directives sometimes when refactoring code when I don't want to create a new branch, or I want different behaviour from compilation symbols. Like, for example, to prevent any caching while debugging, or some other condition.

#if STRONGER_CACHING
Dictionary cache = new Dictionary();
#endif

public object MyMethod(string key)
{
  object value = null;
#if STRONGER_CACHING
    if(!cache.TryGetValue(key, out value))
        cache[key] = value = //...get from data store
#else
    value = //...get from data store
#endif
  return value;
}
 
Simon Colmer
9/25/2012 11:23:17 PM
We call them build flags at my work, as they only do stuff depending on the build configuration (e.g debug)

And example where we have had to use these in the past is to handle some horribly written libraries from ComponentOne where the win-forms and web-forms dlls had exactly the same namespaces that would cause ambiguous name referencing. So when building a shared dll under a win-forms configuration, we used build flags to point to a correct wrapper class.

It was extremely horrible and we walked away from those libraries as soon as we could. 
Jean-Yves
9/25/2012 11:56:05 PM
Hi, 

First of all, thank you for all your posts they are great!!! (answers from people toooo :p)

For the preprocessor directives I have examples... with the "#if DEBUG". My software is protected by a hardware key. 
So if I don't pluged my key into the computer than my software will stop. In development mode, this is a pain in the ass!!! 
It's also really usefull in debug mode to go where the application crash (yes sometime it crash...) but for user you want a nice error message... so here is how I start my app:


	    var haveToCheckHardwareKey = true; 
#if DEBUG    
            haveToCheckHardwareKey = false;
            Application.Run(new Screen.Principale(haveToCheckHardwareKey));
#else
            try
            {
                Application.Run(new Screen.Principale(haveToCheckkey));
            }
            catch (Exception ex)
            {
                MessageBox.Show("Sorry... blablabla...", "Error");
            }
#endif


//JYC 
Steve Crane
9/26/2012 12:42:00 AM
I've used them in the past when writing libraries that build both Windows and Silverlight versions. As Silverlight only supports a subset of .NET you sometimes need to code things differently and can take advantage of the fact that SILVERLIGHT is defined for Silverlight projects. So you end up with code like


#if SILVERLIGHT
  // Silverlight specific code
#else
  // normal code
#endif


Depending on which project is being built you get the correct code for it. 
James Curran
9/26/2012 1:15:22 AM
In C and C++ the preprocessor is  much more powerful than it is in C#.  You could use it to write "macros" which look like functions, but are handled by simple text substitution:

#define square(x) (x*x)

int twentyfive = square(5);

Now, in the early days, there was four distinct steps in compiling C code : Preprocessor, compiler,  assembler, linking.

The preprocessor , as it's name implies, runs first, and handles the directive.  The output of the above would be :

int twentyfive = (5*5);

The preprocessor knows nothing about the syntax of C, and could actually be used on non-C/C++ text files.

The compiler, in those days, would output assembler code (as a text file). The assember would create the actual binary output.  The linker merges in external libraries.  (The C# compiler blurs these steps together).

Preprocessor macros were always a problem, since they don't follow scoping and naming rules, and are just simple text substitution.  If you used the above macro like this:

int xyxy = square(x+y);

and you'll get:

in xyxy = (x+y*x+y);

which is not the value I'd expect.  In fact, you could write:
char* shello = square("Hello");

which will happily give you 

char* shello = ("Hello" * "Hello");

which is just a syntax error. 
Steve Crane
9/26/2012 1:22:21 AM
Reply to: James Curran
Right, I used to use macros like that in C quite a bit. They were a bit like C# generic methods but not as safe, as you mention. 


Last modified on 2012-09-24

comments powered by Disqus