• No results found

The Preprocessor

In document Basic c# (Page 103-108)

System.Console.WriteLine(@"hi bye");

} } Output hi bye

Placing an @ in front of the string lets it spawn multiple lines and the spaces shown in the output. If you want the \ to lose its special meaning in a string, preface that string with a @ sign.

a.cs class zzz {

public static void Main() {

string a = "bye";

string b = "bye";

System.Console.WriteLine(a == b);

} } Output True

The above example displays true, even though the two strings may be stored in different areas of memory. The two strings contain the same characters and hence are similar.

The Preprocessor

Before the C# compiler can start, a small part of it called the pre-processor first activates itself. It is called the preprocessor as the same concept existed in the programming language 'C'. All that the preprocessor does is that it looks at those lines beginning with a # symbol.

a.cs

#define vijay class zzz {

public static void Main() {

} }

The first preprocessor directive we are learning is called define. This lets us create a word/variable or even better, an identifier called vijay. The identifier vijay has no value other than true.

a.cs class zzz {

public static void Main() {

#define vijay }

}

Compiler Error

a.cs(5,2): error CS1032: Cannot define/undefine preprocessor symbols after first token in file

We cannot use the #define, after valid C# code has been written. They have to come at the beginning of the file.

a.cs

#define vijay class zzz {

public static void Main() {

#if vijay

System.Console.WriteLine("1");

#endif } } Output 1

As a #define creates a variable, its value can be checked by the if or more precisely the #if which works in the same way as the if of C# does. Thus the #if is true and all code up to the #endif gets added to the code.

a.cs class zzz {

public static void Main() {

#if vijay

System.Console.WriteLine("1");

#else

System.Console.WriteLine("2");

#endif } } Output 2

The same rules as before for an else. Here as we have not created an identifier called vijay, it gets a value of false and therefore the #if is false. Imagine a preprocessor identifier as a boolean variable.

Why use a preprocessor variable instead of a normal one?

Run the C# compiler as follows on the above program and observe the change in output.

csc /D:vijay a.cs Output

1

The output displays 1 as the /D compiler option lets you create identifiers at the time of compiling the program. This cannot be done with a normal variable. We can add/subtract lots of code form our program, at the time of compilation.

a.cs

#undef vijay class zzz

{

public static void Main() {

#if vijay

System.Console.WriteLine("1");

#else

System.Console.WriteLine("2");

#endif } } Output 2

As we are allowed to create an identifier vijay by the define, the undef does the reverse. It sets it to false which is the default in any case. As the value of vijay is false, the else gets activated. However we run the above as csc /D:vijay a.cs, we are first creating an identifier vijay at the command line prompt, then undefining it at the first line in the program and the output will show 2 as before. You cannot use the define or undefine after real code.

a.cs

#define vijay

#undef vijay

#undef vijay class zzz {

public static void Main() {

#if vijay

System.Console.WriteLine("1");

#endif } }

People are allowed to nag you as many times as they like. Repetition has been part of human history since ancient times. You are allowed to undef as many times as you like even though it makes no logical sense.

a.cs

#define vijay

#define mukhi class zzz {

public static void Main() {

#if vijay

#if mukhi

System.Console.WriteLine("1");

#endif

#endif } } Output 1

You can have as many #if's within #if's. We call them nested if's. If the #if is true, then the text up to the

#endif is included.

a.cs

#define vijay class zzz {

public static void Main() {

#if vijay

System.Console.WriteLine("1");

#else int int;

#endif } }

We get no error at all in spite of the fact that we are not allowed to create a variable called int. Is C#

sleeping at the wheel? It is not as the preprocessor realized that the identifier vijay is true, it removed all the code from the #else to the #endif. C# did not flag an error at all, as it was not allowed to see the offending code by the preprocessor.

a.cs class zzz {

public static void Main() {

#if vijay

System.Console.WriteLine("1");

#else int int;

#endif } }

Compiler Error

a.cs(8,5): error CS1041: Identifier expected, 'int' is a keyword a.cs(8,8): error CS1001: Identifier expected

Now we see the error as the identifier vijay is false. Remember what the C# compiler sees is what the preprocessor allows it to. You write code and what the compiler sees may be very very different.

a.cs

#warning We have a code red class zzz

{

public static void Main() {

} }

Compiler Warning

a.cs(1,10): warning CS1030: #warning: 'We have a code red'

Whenever we want a warning message to be displayed at the time of compiling our code we use

#warning.

a.cs class zzz {

#warning We have a code red public static void Main()

{ } }

Compiler Warning

a.cs(3,10): warning CS1030: #warning: 'We have a code red'

Unlike the #define, the #warning can be used anywhere in our program. It enables us to add to the messages of the compiler. Also the line number changes from 1 to 3 telling us where the warning occurred.

a.cs class zzz {

#error We have a code red public static void Main() {

} }

Compiler Error

a.cs(3,8): error CS1029: #error: 'We have a code red'

Wherever we have warnings, errors cannot be far behind. The difference is that an error unlike a warning, stops everything in its tracks and does not let the compiler proceed ahead. No exe file is created. Normally an error or warning would be placed in an if statement as follows.

a.cs

#define vijay

#define mukhi class zzz {

#if vijay && mukhi

#error We have a code red

#endif

public static void Main() {

} }

Compiler Error

a.cs(6,8): error CS1029: #error: 'We have a code red'

The && means and. The if is true if both sides of the && is true. They are in this case. Remove one of the above #defines and the if will be false.

a.cs

#line 100 "vijay"

class zzz {

#warning We have a code red public static void Main() {

} }

Compiler Warning

vijay(102,10): warning CS1030: #warning: 'We have a code red'

The line directive does two things. One it changes the line number from 1 which is what is should be at the beginning to 100. Thus the warning appears on line 102 now and not 2. Also the file name changes from a.cs to vijay. You have total control over the line number and file name displayed.

a.cs

#line 100 "vijay"

class zzz {

public static void Main() {

int int;

#line 200 "mukhi"

char char;

} }

Compiler Error

vijay(104,5): error CS1041: Identifier expected, 'int' is a keyword vijay(104,8): error CS1001: Identifier expected

mukhi(200,6): error CS1041: Identifier expected, 'char' is a keyword mukhi(200,10): error CS1001: Identifier expected

Line does not only work with the #error or #warning. It affects also the compiler's error line number and file name.

You are allowed to have as many #lines as you prefer.

---7

In document Basic c# (Page 103-108)