Preprocessor macro definitions used with C function definition - c

I'm studying the SQLite source code (in c), but there are some things I can't figure out what they are, and I hope you can give me a hand.
I know c, c++ and JAVA basics but I have never seen something like this and I don't know how to search for it.
In a c file, there are the next definitions (among others):
#ifndef SQLITE_CDECL
# define SQLITE_CDECL
#endif
#ifndef SQLITE_API
# define SQLITE_API
#endif
And then the above definitions are used like this:
SQLITE_API int SQLITE_CDECL sqlite3_conf(int, ...){
//code
I know "SQLITE_API" and "SQLITE_CDECL" are not the return types, function names, keywords, K&R style nor variable modificators...
Why are this words placed like that in the function? What are they for?

They're used to modify the attributes of the functions on different platforms or when building certain ways. Most of the time there may be no need for them, but in certain situations they may be useful, e.g. using __declspec(dllexport) when building a DLL or using static when including the file directly instead of having the linker perform linkage between the object files.

These two declarations look like they exist so that they can be defined differently to support certain quirks of development on Windows. Note that on the #define lines, they aren't defined to any value. This means that they will be replaced with nothing that the parser sees. So, SQLITE_API int SQLITE_CDECL sqlite3_conf(int, ...){ will end up being reduced to int sqlite3_conf(int, ...){ after the preprocessor runs. On Windows, they can be defined differently to support building DLLs with __declspec (see https://msdn.microsoft.com/en-us/library/dabb5z75.aspx) and specifying calling conventions (see https://msdn.microsoft.com/en-us/library/zkwh89ks.aspx).

Related

Need help deciphering C syntax

I have worked on several projects in college on C, but never used it in professional capacity.
Recently I started reading through cpython's source code and the following syntax confused me: github
What does PyAPI_FUNC(int) PyToken_OneChar(int); the part before the function name mean? Is it a wrapper function that dynamically constructs the return type?
I am not even sure what to Google search for, in this case!
PyAPI_FUNC() is a macro defined in pyport.h. The particular definition depends on the platform you're building on, but here's an example:
#define PyAPI_FUNC(RTYPE) __declspec(dllimport) RTYPE
So the line in your question, PyAPI_FUNC(int) PyToken_OneChar(int); expands to:
__declspec(dllimport) int PyToken_OneChar(int);
Basically, it just declares the name PyToken_OneChar as a function that takes an int as its parameter and returns an int, but it does it in a way that lets the compiler embed storage information with those types. See What is __declspec and when do I need to use it? for more information about the __declspec directive if you're interested. Another of the definitions for PyAPI_FUNC is:
#define PyAPI_FUNC(RTYPE) RTYPE
which skips all that and just expands the line above to:
int PyToken_OneChar(int);
So the main thing to take away from this is that source code that's meant to compile on multiple platforms often uses macros that make it easier to write code once and use it on each of those platforms. In this case, it lets the programmers write declarations for PyToken_OneChar() and many other functions once instead of having to write (and maintain!) different versions for each platform. This is fairly advanced stuff -- not something you should worry about if you're getting started.
It's a C Macro they wrote which allows them to do different things on different OS platforms, for instance, on windows, this will export the function as part of the public interface for a DLL.

Can i write preprocessor directives anywhere in my c program?

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.

Keep functions private into a lib in C

I recently had to face a fairly complex issue regarding lib management, but I would be very surprised to be the first one.
Let's imagine you are creating a library (static or dynamic) called lib1 in C. Inside lib1 are a few functions that are exposed through an API, and a few other ones which remain private.
Ideally, the private functions would be static. Unfortunately, let's assume one of the source files, called extmod.c, come from another project, and it would be beneficial to keep it unmodified. Therefore, it becomes unpractical to static the functions it defines.
As a consequence, all the functions defined into extmod are present into lib1 ABI, but not the API, since the relevant *.h is not shipped. So no one notice.
Unfortunately, at later stage, someone wants to link both lib1 and another lib2 which also includes extmod. It results in a linking error, due to duplicate definitions.
In C++, the answer to this problem would be a simple namespace. In C, we are less lucky.
There are a few solutions to this problem, but I would like to probe if anyone believes to have found an efficient and non-invasive way. By "non-invasive", I mean a method which avoids if possible to modify extmod.c.
Among the possible workaround, there is the possibility to change all definitions from extmod.c using a different prefix, effectively emulating namespace. Or the possibility to put the content of extmod.c into extmod.h and static everything. Both method do extensively modify extmod though ...
Note that I've looked at this previous answer, but it doesn't address this specific concern.
You could implement your 'different prefix' solution by excluding extmod.c from your your build and instead treating it as header file in a way. Use the C pre-processor to effectively modify the file without actually modifying it. For example if extmod.c contains:
void print_hello()
{
printf("hello!");
}
Exclude this file from your build and add one called ns_extmod.c. The content of this file should look like this:
#define print_hello ns_print_hello
#include "extmod.c"
On compilation, print_hello will be renamed to ns_print_hello by the C pre-processor but the original file will remain intact.
Alternatively, IF AND ONLY IF the function are not called internally by extmod.c, it might work to use the preprocessor to make them static in the same way:
#define print_hello static print_hello
#include "extmod.c"
This should work for you assuming you have control over the build process.
One way you can do prefixing without actually editing extmod.c is as follows:
Create a new header file extmod_prefix.h as:
#ifndef EXTMOD_PREFIX_H
#define EXTMOD_PREFIX_H
#ifdef LIB1
#define PREFIX lib1_
#else
#ifdef LIB2
#define PREFIX lib2_
#endif
#endif
#define function_in_extmod PREFIX##function_in_extmod
/* Do this for all the functions in extmod.c */
#endif
Include this file in extmod.h and define LIB1 in lib1's build process and LIB2 in lib2.
This way, all the functions in extmod.c will be prefixed by lib1_ in lib1 and lib2_ in lib2.
Here's the answer (in the form of a question). The relevant portion:
objcopy --prefix-symbols allows me to prefix all symbols exported by
an object file / static library.

C: Are #define directives global?

I'm somewhat confused by #define statements. In libraries, they seem to be a means of communication across different files, with lots of #ifdefs and #ifndefs.
Having said that, I now have two files file1.c and file2.c compiled together, with #define TEST 10 inside file2.c. Yet, when I use TEST inside file2.c the compiler gives the following error message:
'TEST' undeclared (first use in this function)
Are #define directives global?
#defines are not global, they are just a substitution where ever they are used (if declared in the same compile unit)
They are not globals, they are not symbols, they are irrelevant at linkage, they are only relevant at pre-compilation.
#defined macros are global in that they do not follow normal C scoping rules. The textual substitution from the macro will be applied (almost) anywhere the macro name appears after its #define. (Notable exceptions are if the macro name is part of a comment or part of a string literal.)
If you define a macro in a header file, any file that #includes that header file will inherit that macro (whether desired or not), unless the file explicitly undefines it afterward with #undef.
In your example, file2.c does not know about the TEST macro. How would it know to pick up the #define from file1.c? By magic? Since macros perform textual substitution on the source code, there is no representation of them in the generated object files. file2.c therefore needs to know that substitution rule itself, and if you want that shared across multiple files, that #define needs to live in a common header file that your .c files #include.
If you're asking specifically about how many of the #ifdefs that you see in libraries work, many of them are likely checking against pre-defined macro names provided by the compilation environment. For example, a C99 compiler defines a __STDC_VERSION__ macro that specifies the language version; a Microsoft compiler defines an _MSC_VER macro. (Often these predefined macros start with leading underscores since those names are reserved for the compiler.)
Additionally, most compilers allow defining simple macros as command-line arguments. For example, you might compile your code via gcc -DNDEBUG file1.c to compile file.c with NDEBUG defined to disable asserts.
In case somebody reads this later, and to add some practical information:
Some environments like atmel, vs, or iar, allow you to define global #define directives. They basically pass these defined values to the precompiler in some commandline format.
You can do the same in batch commands or makefiles, etc.
Arduino always adds a board variant (usually located at hardware\arduino\variants) to all compilations. At that point you can create a new board that contains your global define directives, and use it that way. For example, you can define a mega2560(debug) board out of the original mega2560 that contains some debug directives. You will add a reference to that variant in "boards.txt", by copy pasting some text, and properly modifying it.
At the end of the day, you will have to give that global hfile or global directive to the compiler in one way or another.
you should make a file1.h and put your defines there. Then in file2.c
#include "file1.h"
easy as a pie :)

C function seemingly not defined anywhere!

I'm looking at the vim source code, specifically the file normal.c, and I see this function nv_operator being used, but it's not defined anywhere (I grepped the entire src directory)
It's only declared as:
static void nv_operator __ARGS((cmdarg_T *cap));
I've looked up the definition of __ARGS but it's just ... nothing (pretty much)
in vim.h:
#define __ARGS(x) x
So what could be going on? Is this some kind of C technique to create a dummy function or something?
There is a definition present here:
/*
* Handle an operator command.
* The actual work is done by do_pending_operator().
*/
static void
nv_operator(cap)
cmdarg_T *cap;
....
That style of definition is using an identifier list for its parameters. The style is deprecated (obsolescent) but can still be used in C. The identifiers are named in the parameter list, and their type are named in declarations that immediately follow the function declarator but precede the functions body.
The __ARGS macro is there to handle compilers that don't know about prototypes for functions (the other form to declare parameters - with type and name combined directly in the function parameter list). It would then just emit no parameters at all in declarations, i think.
Update: See this code in vim.h:
#if defined(MACOS) && (defined(__MRC__) || defined(__SC__))
/* Apple's Compilers support prototypes */
# define __ARGS(x) x
#endif
#ifndef __ARGS
# if defined(__STDC__) || defined(__GNUC__) || defined(WIN3264)
# define __ARGS(x) x
# else
# define __ARGS(x) ()
# endif
#endif
It's simply a forward declaration, so that the function is known to the C compiler (and can be used (called from other functions)) before it's actually defined (in line 8247). The actual formatting of the definition (which includes newlines) makes it hard to grep for it's existence.
Don't get distracted by the __ARGS macro. It's only a compatibility macro for the different function declaration syntaxes of K&R C vs. ANSI C.
In ANSI C a function declaration must look like this:
int getopt(int, char * const *, const char *);
In the (older) Kernighan and Ritchie C http://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C
int getopt();
Its hard to find because of how it is defined:
nv_operator(cap)
appears on a line by itself.
I am not too sure what is going on, but here are some hints to help you in your search:
First of all, the __ARGS macro seems to be there because there may be versions of C where you shouldn't include the args in the declaration of the functions (Notice that the macro is defined differently depending on other preprocessor symbols... the comments say it).
Secondly, searching for the function nv_operator may not be good enough. The function might be generated by macros and such, so you can't search for an explicit definition.... for example, maybe the "nv" prefix is added by the preprocessor.
Hope this helps.

Resources