Use a macro both in implementation and header and then undefine it - c

I have a macro that should be used both in my source file and header one. However I don't wan't other code linked to the final object to access that macro (more than anything else I don't want the macro to go causing unexpected errors in other files). I thought about using a macro with a long and complicated name that will be unlikely used from other code, however this solution kinda looks ugly to me. Obviously the most simple solution would be to undefine the macro in some way, however if I define the macro in the header and then undefine it – I think – I won't be able to access it anymore from the source file. What should I do?
// hi.h
#define string char *
void greet(string x);
// hi.c
#include "hi.h"
void greet(string x) {
printf("Hi!");
}
Okay, don't kill me, this was just an example, i know #define string char * is horrible.
Last minute thought: Maybe I can underfine the macro at the end of the source file, is this acceptable to do?

I guess you could conditionally "undefine" macro at the end of the header when the a magic macro is not defined. The blessed source file would have to define this macro prior to including a header.
// header.h
...
#ifndef MAGIC_MACRO
#undef string
#endif
// common source
#include "header.h"
// blessed source
#define MAGIC_MACRO
#include "header.h"
This solution will work great as long as no macro defined inside the header uses string macro.

What should I do?
Pick option 1 a macro with a long and complicated name that will be unlikely used from other code as it's the simplest and most obvious. Do not use a complicated name - just use a name so that you and other developers will know it's a private symbol, that's all.
// hi.h
// this macro is private
#define _lib_string char *
Remember about reserved words. Example: https://github.com/GNOME/glib/blob/main/glib/glib-private.h#L32 .
he most simple solution would be to undefine the macro in some way, however if I define the macro in the header and then undefine it – I think – I won't be able to access it anymore from the source file
If you go this way, you'll end up with spaghetti code, where some global state affects what you have. For example:
// hi.h
#define string char *
void greet(string x);
#ifndef FROM_HI_C
#undef string
#endif
// hi.c
#define FROM_HI_C
#include "hi.h"
void greet(string x) {
printf("Hi!");
}
Maybe I can underfine the macro at the end of the source file, is this acceptable to do?
Other files see only the header file - they are unaffected by anything in the source file.

Related

Is there a way to expand macro based on command line arguments? [duplicate]

Following program compiles successfully and print 1000 without even calling a foo() function from our main() function. How is it possible?
#include<stdio.h>
void foo()
{
#define ans 1000
}
int main() {
printf("%d", ans);
return 0;
}
#defineis run by the preprocessor which is staged before the compiler. After the preprocessor is done, the code will look like this:
/* Everything that is inside stdio.h is inserted here */
void foo()
{
}
int main() {
printf("%d", 1000);
return 0;
}
And this is what actually get compiled.
The preprocessor is very important to make header files work. In them, you see this structure:
#ifndef foo
#define foo
/* The content of the header file */
#endif
Without this, the compiler would complain if a header file is included more than once. You may ask why you would want to include a header file more than once. Well, header files can include other header files. Consider this macro, which is useful for debugging. It prints the name of the variable and then the value. Note that you would have to do a separate version for different types.
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
This is pretty versatile, so you may want to include it in a header file for own use. Since it requires stdio.h, we include it.
/* debug.h */
#include <stdio.h>
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
What happens when you include this file and also include stdio.h in you main program? Well, stdio.h will be included twice. That's why debug.h should look like this:
/* debug.h */
#ifndef DEBUG_H
#define DEBUG_H
#include <stdio.h>
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
#endif
The file stdio.h has the same construct. The main thing here is that this is run before the compiler. The define is a simple replacement command. It does not know anything about scope or types. However, as you can see here, there is some basic logic built into it. Another thing that the preprocessor does is to remove all the comments.
You can read more about the C preprocessor here: http://www.tutorialspoint.com/cprogramming/c_preprocessors.htm
The #define is processed by the preprocessor before the compiler does anything. It is a simple text replacement. The preprocessor doesn't even know if the line of code is inside or outside a function, class or whatever [Ref: https://stackoverflow.com/a/36968600/5505997]. Clearly you do not need to call the function to set the value and obviously you will not get any error during compile.
As others have stated, #define is a preprocessor directive, not C source code. See Wiki here.
Point being, in your code #define ans 1000 is not a variable definition, meaning that even if you were calling foo() in the main, you would still not be setting "ans" at runtime, because it is simply not a variable. It is just telling the preprocessor what to do with the "label" "ans", when it finds it in your source code.
In this example, the main() will essentially be calling an empty foo() function:
int main()
{
foo(); // Calls an empty function
printf("%d", ans); // ans will have been substituted by 1000 by the time you start executing you code
return 0;
}
The definition of "ans" will simpy not exist anymore by the time you start executing you main(). This is what the preprocessor does (in part). It finds all the #defines declared in your entire source code and tries to find places in your code where you have used these defines. If you have not used them, it moves on (don't care), if you have, it substitutes the label by the actual defined value.

Using define in a c header file

I am just starting to learn C so hopefully this isn't a dumb question. The problem I am having is regarding header files and using #define for constants. I have read that I should use the following to prevent my header from being compiled more than once.
#ifndef NAME_OF_FILE
#define NAME_OF_FILE
.
. //my header file content
.
#endif
I want to add a constant, and I believe I would also use a #define such as,
#ifndef NAME_OF_FILE
#define NAME_OF_FILE
#define NUM_CONST 5 //the constant I want in my header file
.
.
.
#endif
How does C know that #define NAME_OF_FILE is referring to the .h file while #define NUM_CONST 5 is just a constant? Is it because of the value at the end of NUM_CONST? Or do I have this all completely wrong?
There is no essential difference between the two defines. #define NAME_OF_FILE and #define NUM_CONST 5 are the same sort of thing. They define a plaintext replacement of tokens (in the first case, the replacement is nothing).
For example you could put subsequent code:
printf("%d\n", NAME_OF_FILE NUM_CONST NAME_OF_FILE);
and after the above substitutions the code would turn in to:
printf("%d\n", 5);
which is correct. There is no "magic". The compilation step that performs these substitutions is usually known as "preprocessing".
NAME_OF_FILE does not refer to the .h file, per se, but the use of the ifndef directive achieves the goal of not compiling the same code twice.
It doesn't. NAME_OF_FILE could be anything. You could have
#ifndef PRETTY_PINK_PRINCESS
#define PRETTY_PINK_PRINCESS
/* definitions */
#endif
And it would work just as well. Using NAME_OF_FILE is just a convention because it makes it likely that it's unique.
#define IDENTIFIER defines the identifier for the sakes of #ifdef, but what it is being defined to is the empty string.
So,
#define NAME_OF_FILE
int main()
{
int x = NAME_OF_FILE;
}
would resolve to
int main()
{
int x = ;
}
So there is no "knowing" involved, just a defined-but-empty.
(That is why some style guides out there recommend #define NAME_OF_FILE NAME_OF_FILE, so that if NAME_OF_FILE happens to be used in the source, it is replaced-with-self by the preprocessor.)
For the compiler both these statement are the same type a macro
#define NAME_OF_FILE
#define NUM_CONST 5
That this construct
#ifndef NAME_OF_FILE
#define NAME_OF_FILE
.
. //my header file content
.
#endif
is doing, is that the header is processed for the first time, the marco "NAME_OF_FILE" is n ot defined, hence it get defined and the whole header file content processed. The second time the compiler comes around this, because the header was included in project more than once, is that the marco is defined now and the header file doesn't get processed again.
Again, the "c-code" is not aware, that the marco __TEST_H for example has its because the header file's name is 'test.h'. What you are reffering to is probably, that your IDE auto-generated the marco then you created the header file and that the IDE called the marco after the file for the user's convenience. Like a another one here allready said, that you can rename the marco (rename it in the whole project I mean by that) and the code would compile and generally behave exactly like before.

What does #define __UNUSED__ do?

I am going through a C code and I found something like this:
#define __UNUSED__
char buf[MAX_BUF_LENGHT];
int errors=0;
What does this mean?
I am not aware that __UNUSED__ is a predefined preprocessor symbol. So it must be a user defined symbol.
I myself have sometimes (test) code or obsolete code in a c-file that I mark-out with #ifdef BLIEP (and BLIEP is normally not defined), but can put it back into compilation by placing a #define BLIEP. Probably the original author of this code did something similar with __UNUSED__.

What does the include in the middle of code in C?

Please,
could you tell me what does the code below do?
...code...
#include file.h
...code...
I was used to put includes a the beggining of each file. I have never seen this before and also wasn't able to find anything in the internet.
#include is a pre-processor directive that takes the file given as the argument and dumps its contents in the current file. Typically, this is used to include definitions of commons functions from header files, but there's no necessity to use it in that way.
It's usage is not limited to the starting of the file, but note that the variables, macros or functions declared in this header will not be usable before the include statement even if on the same file.
As everyone tells you #include can be used every where (provided it is on its own logicial line). And there are cases where you want to #include several times the same file. Read first the X macro wikipage, and the C preprocessor wikipage.
And I have a concrete example in my MELT monitor (related to MELT ...).
I have a predef-monimelt.h (generated) file containing lines like
MOM_PREDEFINED_NAMED( name, id,hash) e.g.
MOM_PREDEFINED_NAMED(GET,_9dsak0qcy0v_1c5z9th7x3i,1573018885)
MOM_PREDEFINED_NAMED(HEAD,_47fatww79x6_vh8ap22c0ch,3922245622)
MOM_PREDEFINED_NAMED(web_handler,_7sav6zery1v_24sa6jwwu6c,2339220870)
#undef MOM_PREDEFINED_NAMED
My monimelt.h file (a real header file) define external pointers and an enum, so has notably:
// declare the predefined
#define MOM_PREDEFINED_NAMED(Name,Id,H) extern momitem_t* mom_named__##Name;
#include "predef-monimelt.h"
/// declare the hash of the predefined as an enum
#define MOM_PREDEFINED_NAMED(Name,Id,H) mom_hashname__##Name = H,
enum {
#include "predef-monimelt.h"
};
My main.c file contains notably a routine :
// if this routine is compiled, we are sure that all predefined hashes
// are unique
const momitem_t *
mom_predefined_item_of_hashcode (momhash_t h) {
switch (h) {
#define MOM_PREDEFINED_NAMED(Nam,Id,Hash) case Hash: return mom_named__##Nam;
#include "predef-monimelt.h"
default:
return NULL;
}
}
but my items.c includes the predef-monimelt.h file twice (to create the predefined items at initialization, and to define their variables):
void mom_create_predefined_items (void) {
int nbnamed = 0;
#define MOM_PREDEFINED_NAMED(Nam,Id,H) do { \
mom_named__##Nam = mom_make_item_of_identcstr(#Id); \
mom_named__##Nam->i_space = momspa_predefined; \
mom_register_item_named_cstr (mom_named__##Nam, #Nam); \
nbnamed ++; \
} while(0);
#include "predef-monimelt.h"
} // end of mom_create_predefined_items
// declare the predefined
#define MOM_PREDEFINED_NAMED(Nam,Id,H) momitem_t* mom_named__##Nam;
#include "predef-monimelt.h"
FWIW, the MELT monitor is GPLv3+ licensed software

Include header file in C curiosity

I have the following curiosity about the include files and how they are managed (with GCC):
Let's say I have one source file foo.c and three headers foo.h, foo_cfg.h and foo_int.h.
In foo.c:
#include "foo.h"
#include "foo_int.h"
In foo.h:
#include "foo_cfg.h"
In foo_cfg.h:
/* no inclusions */
#define FOO BAR
In foo_int.h:
/* no inclusions */
#define BAR 0U
I am wondering why the compilation succeeds. Shouldn't the foo_cfg.h file complain that it doesn't know about BAR symbol?
Furthermore I have another source file bar.c which only includes the foo.h file and still works.
Remark: this is from a project I am working on with a complex build environment of which I don't have to much details. Could it be that the build environment has an effect on this other than specifying the location for the header files?
It might be that the question is really stupid or I've overlooked something and I apologize if so.
No, it's ok.
You see, the preprocessor doesn't care if BAR is defined or not at all. It just replaces the string FOO with BAR in the source code which follows, without actually caring if it's defined at that point or not.
Next, at the actual .c file (the thing where the compilation starts) both headers are included, so the compiler sees both substitutions: FOO -> BAR and BAR -> 0U. So it successfully applies both of them.
The headers are never compiled alone, they are always compiled as a part of .c file which #includes that header. (The preprocessor just pretends that the content of the header is pasted to the place where #include is located.) So, for the preprocessor your file foo.c looks like this:
/* no inclusions */
#define FOO BAR
/* no inclusions */
#define BAR 0U
/* the rest of the file... */
/* for example: */
unsigned int i = FOO;
And the compiler after the preprocessing sees just this:
/* no inclusions */
/* no inclusions */
/* the rest of the file... */
/* for example: */
unsigned int i = 0U;
(not quite sure, maybe the preprocessor removes the comments as well.)
Edit:
Indeed, as #pmg mentions, the preprocessor replaces comments with a whitespace, so the real preprocessed text which is fed to the compiler is just
_
_
_
_
unsigned int i = 0U;
(here _ denotes a whitespace)
To extend Vlad's answer a bit:
Preprocessor macros are expanded when used, not when defined.
So when you write #define FOO BAR, all it does is remember that FOO=BAR.
When you write #define BAR 0U, it remembers that BAR=0U.
Now, when FOO is seen in the code, it's replaced with BAR, which is immediately replaced with 0U.
The order in which #define FOO and #define BAR appear in the source is unimportant. The important thing is that when FOO is seen the first time, both definitions were already done.

Resources