What is a macro in C programming


10.2 Macros and Constants - »#define«

With #define it is possible to specify character strings that are exchanged for another character string before the program is compiled. You will surely remember how a program is translated from the previous chapter. Here, too, the # character causes the preprocessor to do its work first before the compiler translates the emerging program into assembler and then into machine language. The syntax of the define directive looks like this:

#define identifier substitute identifier #define identifier (identifier_list) substitute identifier

A symbolic constant is defined in the first syntax description and a macro in the second case.


10.2.1 Symbolic constants with »#define«

Here you can see a first program example that defines a symbolic constant:

/ * define1.c * / #include #include #define ONE 1 int main (void) {printf ("% d \ n", ONE); return EXIT_SUCCESS; }

Each symbolic constant ONE is defined with the value 1 in the program. When you compile the program, all names with ONE in the source text are replaced by the value 1 by the preprocessor before compilation. You do not have to write the constant ONE in capital letters as in the example. This is only for a better overview. But be careful, the following does not work:

In this case, the string "ONE" is actually output on the screen and not the value 1. This means that the constant ONE is not replaced by 1 here.


Notice

Note that #define macros are constants. Once the constants have been set, they can no longer be changed while the program is running.


What are the advantages of such defines? This is to demonstrate the following program:

/ *kreisber.c * / #include #include / * On Linux, the compiler flag -lm * must be specified for math.h: * gcc -o synkonst2 symkonst2.c - lm * / #include #define PI 3.1415926f / * Program for the calculation of circular area (A), diameter (d) * and circumference (U) and diameter from circumference * / void circle surface (void) {float A , d; printf ("Enter the diameter of the circle:"); scanf ("% f", & d); A = d * d * PI / 4; printf ("The area of ​​the circle is% f \ n", A); } void diameter (void) {float A, d; printf ("Enter the area of ​​the circle:"); scanf ("% f", & A); d = (float) sqrt ((double) 4 * A / PI); printf ("The diameter of the circle is% f \ n", d); } void circumference (void) {float U, d; printf ("Enter the diameter of the circle:"); scanf ("% f", & d); U = d * PI; printf ("The circumference of the circle is% f \ n", U); } void d2circumference (void) {float U, d; printf ("Enter the circumference of the circle:"); scanf ("% f", & U); d = U / PI; printf ("The diameter of the circle is% f \ n", d); } int main (void) {circle (); diameter(); circumference (); d2circumference (); return EXIT_SUCCESS; }

In this program simple calculations of circular areas are carried out. Instead of specifying PI at every point in the program, text replacement using define is more suitable here. This also guarantees that the same value is always used throughout the program. Should you z. If, for example, you need a more precise specification of PI, you only have to change the symbolic constant.

Another advantage is z. B. the use of certain constants, such as a national currency. If a change becomes necessary, it can be made at a central point without much effort for the entire program. You can also use previously defined names for macro definitions, as in the following example:

#define PI 3.141592653 #define PI_2 PI * 2

Here PI is defined first and in the next line the value of PI * 2, which is replaced textually by PI_2.


tip

Avoid unnecessary calculations when replacing text. For example, a define of the type #definePIatan (1) * 4 causes this value to be recalculated in the program every time. For such cases it is better to use a const variable such as:

constdoublePI = atan (1) * 4;


With the #define directive, not only numbers can be specified as symbolic constants, but also strings. Example:

#include #define INTEGER int #define WRITE printf (#define END); #define INPUT scanf (#define ENDESTART return 0; #define NEWLINE printf ("\ n"); #define START int main () #define BLOCKANFANG {#define BLOCKENDE}

With these specifications, a small programming language of its own was created with minimal effort! For example, a program in the new language could look like this:

START START OF BLOCK INTEGER number; WRITE "Hello World" END NEW LINE WRITE "Number input:" END INPUT "% d", & number END WRITE "The number was% d", number END END START BLOCKING

Not really a new programming language was created here. Instead of int main (), the program simply writes START, or instead of return 0, ENDESTART is written. Before the compiler is translated, the preprocessor replaces the pseudo-language back to C.

This pseudo-language is now to be packed into its own header file. To do this, create a new source file with the following content:

/ * mysyntax.h * / #ifndef MYSYNTAX_H #define MYSYNTAX_H #include #include #define INT #define WRITE printf (#define END); #define INPUT scanf (#define ENDESTART return EXIT_SUCCESS; #define NEWLINE printf ("\ n"); #define START int main () #define BLOCKANFANG {#define BLOCKENDE} #endif / * MYSYNTAX_H * /

Save these lines of code under the name MYSYNTAX.H. Now the main program including the new header file follows:

/ * my_C.c * / #include "mysyntax.h" START START OF BLOCK INTEGER number; WRITE "Hello World" END NEW LINE WRITE "Number input:" END INPUT "% d", & number END WRITE "The number was% d", number END NEW LINE END START BLOCKING END

Save the main program in the same directory as mysyntax.h. You can freely choose the name for the main program, for example: my_C.c. Compile this program. If the header file mysyntax.h is in a different directory than the main program, the compiler must be informed of this. If the header file is e.g. B. in / home / myhome / myheader, this is communicated to the preprocessor as follows:

#include "/home/myhome/myheader/mysyntax.h"

On MS Windows systems it must look like this (C: \ be your work drive):

#include "c: \ Program Files \ mysyntax.h"

10.2.2 Macros with »#define«

You can also use the define directive to write parameterized macros. An example:

/ * define2.c * / #include #include #define SMALLER_100 (x) ((x) <100) void klHundert (int number) {if (SMALLER_100 (number)) printf ( "Yes! The number is less than 100! \ N"); else printf ("The number is greater than 100! \ n"); } int main (void) {int b = 99; klHundert (b); return EXIT_SUCCESS; }

You can recognize a parameterized macro by the fact that the macro name is followed by a bracket:

#define SMALLER_100 (x) ((x) <100)

Standalone macros do not need a semicolon at the end of the line when used in the program. Macros can often be recognized by this. The compiler does not complain if you set semicolons anyway; but it is not necessary.

In the case under consideration, you have the formal parameter x. This can be used as often as you like on the right-hand side of the macro. Please note that this formal parameter must also be in brackets on the right-hand side. The following definition would be wrong:

#define SMALLER_100 (x) (x <100)

because here the parameter x is not between brackets. The line

looks like this after the preprocessor run, i.e. before the actual compilation:

Another frequently used variant of this type is:

#define MAX (x, y) ((x) <= (y)? (y): (x))

Two arguments are used as parameters here. Both parameters are separated from each other by a comma. With this macro, the larger of the two decimal numbers is determined. Another example:

#define EXCHANGE (x, y) {\ int j; \ j = x; x = y; y = j; \}

This macro swaps two integer values. This example also shows how a macro with several statements can extend over several lines. When defining a macro, a backslash must be written at the end of each line.

Long macros that are accessed frequently can, however, bloat the code unnecessarily. In such a case, functions are more suitable. Here is a negative example:

/ * bad_define1.c * / #include #include #define MUCH_TEXT "TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextText" \ "TextTextTextTextText" \ "TextText \" TextText ); printf (MUCH_TEXT); printf (MUCH_TEXT); return EXIT_SUCCESS; }

This program would look like this after the preprocessor run and before the compiler run:

/ * bad_define2.c * / #include #include int main (void) {printf ("TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextTextText); printf ("TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText \ n"); printf ("TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText \ n"); return EXIT_SUCCESS; }

Now the same example with a function that is the more efficient method in this case:

/ * without_define.c * / #include #include void a lot of text (void) {printf ("TextTextTextTextTextTextTextTextTextText" \ "TextTextTextTextTextTextTextTextTextText" \ "TextText \TextText" TextText \TextText "); } int main (void) {a lot_text (); much_text (); much_text (); return EXIT_SUCCESS; }

Incidentally, the define directive is a directive intended purely for the C programming language. A pure C ++ compiler will therefore not recognize and compile define. Most compilers know both C and C ++.

As a rule, there should be no problems compiling here. This is only in addition to the topic, if you want to get to know the basics in C and then continue with C ++. Under C ++ and the new ANSI-C99 standard, smaller function macros can also be replaced by inline functions.


Note

The scope of symbolic constants or macros extends from the point of declaration with #define to cancellation with #undef. The cancellation using #undef is optional. If #undef is not used, the scope extends to the end of the file.




your opinion

How did you like the Openbook? We always look forward to your feedback. Please send us your feedback as an e-mail to [email protected]