I am trying to understand the idea of function like Macros however there are a few points that befuddle me. For example say we have:
#define Max(a,b) ((a)>(b)) ? (a):(b))
and I call it like such
int i = Max(4,5);
This will evaluate a conditional expression equivalent to a>b? If yes then a, else b. But I'm confused as to how the Max function knows what to do with the arguments. Unlike an actual function, the implementation isn't written in code in the calling program. is the statement to the right of the define statement doing this for me? Its just a new thing for me and I want to make sure I understand what is happening here.
This particular part of function like macros confuses me. I know that these types of macros are useful for reducing overhead costs since they exclude the JSR RTS processor instructions which saves memory on the stack.
#define Max(a,b) ((a)>(b)) ? (a):(b))
is a macro, that causes nothing else but a simple textual replacement within your code, which means that during the preprocessing this line:
int i = Max(4,5);
is changed into:
int i = ((4)>(5)) ? (4):(5));
Note that there is no type safety while working with macros like this one and you will have really hard time while debugging your code as well. Good rule of thumb is: Don't use macro when you can achieve the same with function:
int max(int a, int b) {
return (a > b) ? a : b;
}
What the compiler actually sees, after preprocessing, is:
int i = ((4)>(5)) ? (4):(5));
The parameters passed to the macro are substituted into the body of the macro.
Just stop thinking about macro like compilable code. Macros are "resolved" by pre-processor, not actually during compilation stage. So by macro definitions you just define how to process certain string in text file. Only output of pre-processor is passed to compiler. You can use gcc -E to see your source after pre-processor. It is still C code on this stage but without any preprocessor directive.
Hope this will help you.
try to build your code with the gcc -E and see how your code look before compiling it
In fact in the build process the compilator transform your actual code to a preprocessor code.
In the preprocessor phase the compilator replace all macro in your c code with its content and generate another code called preprocessor code and then the compilateor generate the object code from the preprocessor code
The gcc -E allow you to see your preprocessor code
Related
i am currently looking at the HarmonyOS source code, and I can up with a problem. In the image I know that the function doesn't return anything, but what's the LITE_OS_SEC_TEXT part? I havent seen this keyword before, or is it even a keyword like STATIC or typedef. And if so, how do you define a keyword in C?
how do you define a keyword in C?
You don't. It's impossible.
What you can do is to use macros. They are basically just advanced text replacement. The preprocessor is run before the compiler. That is, in principal. On modern compilers they are run at the same time, but the behavior is the same.
If you want to look at the source code after the preprocessor, you can use the -E parameter to the compiler.
Here is an example of how you can make C code more like Pascal. DON'T DO THIS! JUST FOR FUN!
#include <stdio.h>
#define Begin {
#define End ;}
#define Writeln(X) puts(X)
int main(void)
Begin
Writeln("Hello, World!");
Writeln("Hello again")
End
Probably it is a macro. You should look for it's definition in included header files.
You can read about macros here.
Is it mandatory to write #include at the top of the program and outside the main function?
I tried using #define preprocessor inside the main function and it worked fine with only one exception..that being the constant which i defined using the define directive can be used only after the line #define
For instance say printf("%d",PI); #define PI 3.14will give error "Undefined symbol PI". But in the following code i did not encounter any error
#define PI 3.14
printf("%d",PI);
Is this because C is a procedural language and procedural languages implements top down approach?
Also i would like to know that can we use only #define inside the main function or other preprocessor directives too? If we can use then which ones?
Or is it the other way around, instead of #include we can use all the preprocessor directives in the main function?
The only place you can't put a preprocessor directive is in a macro expansion. The sole exception is #pragma, which can also be written _Pragma().
This has nothing to do with "procedural", but due to the fact that C is defined in terms of 8 translation phases, each of which is "as-if" fully-completed before the next phase. For more details, see the C11 standard, section 5.1.1.2.
One example of when it is useful to use preprocessor directives after the start of a file is for the "X Macro" technique (which many people only know as "those .def files").
Preprocessor directives work pretty much anywhere. Of course, you can make your code confusing pretty easily if you abuse this.
The pre-processor does its work before the compiler performs the source code translation into object code. Pre-processing is mostly a string replacement task, so it can be placed just about anywhere in your code. Of course, if the resulting expansion is syntactically incorrect, the expanded source code will fail to compile.
A commonly tolerated practice is to embed conditional compilation directives inside a function to allow the function to use platform specific APIs.
void some_wrapper_function () {
#if defined(UNIX)
some_unix_specific_function();
#elif defined(WIN32)
some_win32_specific_function();
#else
#error "Compiled on an unsupported platform"
#endif
}
By their nature, the directives themselves normally have to be defined at the beginning of the line, and not somewhere in the middle of source line. But, defined macros can of course appear anywhere in the source, and will be replaced according to the substitution rules defined by your directives.
The trick here is to realize that # directives have traditionally been interpreted by a pre-processor, that runs before any compilation. The pre-processor would produce a new source file, which was then compiled. I don't think any modern compiler works that way by default, but the same principles apply.
So when you say
#include "foo.h"
you're saying "insert the entire contents of foo.h into my source code starting at this line."
You can use this directive pretty much anywhere in a source file, but it's rarely useful (and not often readable) to use it anywhere other than at the start of the source.
I know that probably there is no concept of scope for macros, but please help me understand the following output - which seems to suggest that macros are local to functions:
#include<stdio.h>
#include<stdlib.h>
#define A 100
void fun();
int main()
{
fun();
printf("%d\n",A);
system("pause");
return 0;
}
void fun()
{
#undef A
}
The output of the program is 100 though according to me it should have been a compiler error. Please explain why?
The pre-processor works on the text of your source code and it does it before the compiler proper ever starts to run.
In essence your compiler works on a file that looks like
/* Lots of code from the included files omitted */
void fun();
int main()
{
fun();
printf("%d\n",100);
system("pause");
return 0;
}
void fun()
{
}
So running and printing 100 is exactly what you would expect.
Notice that all the pre-processor directives are gone, and that all instances of A between the define and the undef have been replaced with 100.
The thing to remember is:
The pre-processor runs, changing the text
Then the compiler runs on the result
The preprocessor makes a single pass though the program text at compile time. By the time the program runs all of the directives are long gone.
Originally, the preprocessor was actually a separate program that understood C only to the extent that it parsed tokens the same way. After creating a macro-expanded version of the program as a temporary file, the real compiler was run. Today, it's integrated into the compiler, but in such a way that the effect is the same.
This is how the convention of using all-upper-case macro names began, i.e., in order to emphasize their substantially different nature. You can still get the compiler to output the expanded-but-uncompiled intermediate text. This is occasionally useful when tracking down bugs and understanding complicated conditional compilation.
You can't run preprocessor commands in functions. They're removed from compiled code. That's why they're called preprocessor: they are executed and removed before the program is compiled. In fun(), you are undefining the number 100.
Macros are executed at compile time (in fact before the compiler).
macro expansion is done at preprocessing step, which is a step before compiling.
If you like to see how the code looks after this step, try compile with preprocessing only option.
e.g.
gcc -E myfile.c > myfile.ppout
and read the output.
I added this in my code:
#ifdef DEBUG_MODE
printf("i=%d\n",i);
fflush(stdout);
#endif
and my question is, if I'm not in DEBUG_MODE what the compiler does when compiling this?
The compiler will do nothing, because there will be nothing there when DEBUG_MODE is not defined.
#ifdef and #endif control conditional compilation. This happens during an initial pass over the program, making dumb textual substitutions before the compiler even begins to consider the file to contain C code specifically. In this case, without the symbol defined only whitespace is left. The text is never even lexed into C tokens if the preprocessor define tested for isn't defined at that point.
You can see this for yourself: just invoke your compiler with whatever flag it uses to stop after preprocessing - e.g. gcc -E x.cc - and at that point in the output there will just be an empty line or two. This is also a very important technique for understanding macros, and a good thing to do when you just can't guess why some program's not working the way you expect - the compiler says some class or function doesn't exist and you've included its header - look at the preprocessed output to know what your compiler is really dealing with.
if DEBUG_MODE is not defined, the code under it will not be compiled.
for(x;x<crap;x++)
{
macro(x,y);
}
How is this handled by preprocessor? Is this loop unrolled or something else?
The macro is expanded before the code is compiled - it doesn't matter whether it's in a loop or anywhere else.
#define macro(x, y) doSomething(x, y)
for(x;x<crap;x++){
macro(x,y);
}
will expand to:
for(x;x<crap;x++){
doSomething(x,y);
}
The context surrounding macro(x,y) has no effect on how the preprocessor expands it.
(The preprocessor doesn't even know what programming language you're using - it could be C, Python, Brainfuck or a letter to your bank manager and it would expand macros just the same way.)
#define macros can be thought of as a search and replace before compilation action happens. This means whatever your macro equates to will be directly substituded in its reference inside your code. No, the loop is no unrolled.