I'm currently working with an old C library (made in the early 90's) and the following function declaration made me confused :
#define bland_dll
typedef unsigned short int usint;
typedef unsigned char uchar;
int bland_dll Read_Chan (usint channel);
What is the bland_dll doing between the function's name and it's return type ?
Thanks for your lights!
Its a macro defining empty, so when preprocessed it turns out to be:
int Read_Chan (usint channel);
I suspect, its a holdover from the early days when declaring DLL linkage types, like pascal which has a special meaning to the linker, for example. Another example is __cdecl.
For completion of the idiosyncracies of compiler linkage mechanisms:
__stdcall
__fastcall
__cdecl
Each of them influenced how the linker managed the name decoration at compile time, and may have caused conniptions with linking to third party DLL's due to the differing link time switches.
Edit: Thanks unwind for the correction.
Related
I've come across the following declaration of "size_t" a few times now, but don't really know what this means:
#ifndef __SIZE_T
#define __SIZE_T
typedef unsigned int size_t;
#endif
What exactly is going on here? What is #define __SIZE_T doing? Isn't the typedef alone enough to get the job done?
Identifiers and macros with double underscore or one underscore followed by a capital letter are reserved for the compiler. So __SIZE_T is most likely something internal in the specific compiler. (I think for example gcc/glibc internally uses something called __SIZE_TYPE__.)
The #ifndef ... #define is simply conditional compilation (sometimes called sloppily called "compiler switch", which is also a term used for compiler arguments). It checks if __SIZE_T has already been defined or not. This has to be a separate macro, since you can't do pre-processor checks on types. Something like #ifndef size_t won't work if size_t is a type.
So this seems to be a compiler's internal definition of the standard type size_t for a given compiler and target. Not something the application programmer need to care or worry about.
Typically you would find size_t inside stddef.h, same thing goes with NULL. However, the standard (7.19 and 7.21) states that stdio.h should also define these two. Hence the need for the macro, in case both stddef.h and stdio.h are included in the same program.
As I understand it, function prototypes are intrinsically extern and adding the keyword to them will not change functionality. I was looking at the source code for the Linux Kernel and came across the following:
extern bool console_suspend_enabled;
/* Suspend and resume console messages over PM events */
extern void suspend_console(void);
extern void resume_console(void);
int mda_console_init(void);
void prom_con_init(void);
void vcs_make_sysfs(int index);
void vcs_remove_sysfs(int index);
As you can see, some functions have extern prefixed and some do not. This seemed to be present in a number of header files across the project making me wonder: is this just an inconsistency or is it for some sort of (old) compiler compatibility reason?
Source: https://github.com/torvalds/linux/blob/master/include/linux/console.h#L188
is this just an inconsistency or is it for some sort of (old) compiler compatibility reason?
It's certainly an inconsistency in coding style. But this is harmless since both are equivalent.
The presence or absence of extern keyword for function declarations makes no difference - extern is optional for function declarations.
On the other hand, not providing any declaration can lead to subtle bugs such as implicit function declarations (by the way,implicit declarations are not valid since C99 - Are prototypes required for all functions in C89, C90 or C99?) if the function defined in one compilation unit is used in other compilation unit(s). Using a header file to provide declarations across multiple compilation units is the common practice.
The source code for busybox's syslogd implementation contains some annotations I'm unfamiliar with. The language is C, not C++.
int syslogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int syslogd_main(int argc UNUSED_PARAM, char **argv)
Specifically, MAIN_EXTERNALLY_VISIBLE and UNUSED_PARAM.
What exactly are these annotations doing? Where can I read more about them and other annotations?
Are these part of the C standard, or are they compiler extensions? If they are compiler extensions, how widely supported are they?
I assume the first one is why this file doesn't have a main() function. If these are compiler extensions rather than part of the standard, does this mean this file can't be meaningfully compiled as-is by a compiler that adheres only to the C standard?
Why did they declare a prototype of the syslogd_main function immediately before the full definition? Can the MAIN_EXTERNALLY_VISIBLE annotation only be applied to function prototypes?
1. What exactly are these annotations doing?
See include/platform.h and include/libbb.h
UNUSED_PARAM expands to __attribute__ ((__unused__)). It specifies the variable (argc in your example) as "possibly unused" and disables the "unused variable" warning.
From the GCC manual [Specifying Attributes of Variables]:
unused
This attribute, attached to a variable, means that the variable is meant to be possibly unused. GCC will not produce a warning for this variable.
MAIN_EXTERNALLY_VISIBLE expands to EXTERNALLY_VISIBLE and then to __attribute__(( visibility("default") )). It controls the visibility of the function.
From the GCC manual [Declaring Attributes of Functions]:
... On ELF, default visibility means that the declaration is visible to other modules and, in shared libraries, means that the declared entity may be overridden.
From include/libbb.h:
/* We need to export XXX_main from libbusybox
* only if we build "individual" binaries
*/
#if ENABLE_FEATURE_INDIVIDUAL
#define MAIN_EXTERNALLY_VISIBLE EXTERNALLY_VISIBLE
#else
#define MAIN_EXTERNALLY_VISIBLE
#endif
2. Are these part of the C standard, or ...?
No, those are macros defined in the BusyBox project.
3. I assume the first one is why this file doesn't have a main() function. ...
No. BusyBox combines many utilities into a single executable. That explains the "lack of a main() function" in syslogd.c.
4. Why did they declare a prototype of the syslogd_main function immediately before the full definition? ...
From the GCC manual [Declaring Attributes of Functions]:
The keyword __attribute__ allows you to specify special attributes when making a declaration.
Earlier today I was looking through various header files just to compare them to the ones I was making and noticed that they seem to declare their functions a bit differently.
For example here is the declaration for strlen from string.h:
extern size_t __cdecl strlen(const char *);
Upon doing some research I found that extern is for declaring a variable outside a function block. Is it best practice to declare my functions in header files with extern as well?
I see they use size_t which is unsigned long long here instead of int, I'm assuming that this is because it is more efficient for several reasons (e.g. the length of a string will never be a negative number) but is that the reason they use size_t here? Or am I missing the point completely?
Then finally I see __cdecl which I can't find much information on. What is __cdecl exactly? Should I be using it too?
And finally, I notice that in this declaration there is no variable name for the arguement being passed to strlen. I'm guessing that the reason for this is that this is not a function prototype, just a declaration, and the prototype is elsewhere. Why are there no variable names e.g. strlen(const char *str) in the declaration?
And my last question is what would the function prototype for strlen look like if this is just a declaration? My guess is something like:
size_t strlen(const char *str)
I am just asking because I want to learn and improve my code (assuming I am making function prototypes/declarations in a C file, and then just function declarations in a header file so that other C files can utilize them).
size_t is more appropriate returned value for strlen rather than int
__cdecl is a calling convention for a function. This signifies who sets up a stack for parameters, return value etc and who clears it. More reference: Calling convention
While declaring a function, you don't really need parameter names. Just parameter type is sufficient.
Update for extern :
extern tells to compiler that the statement is just a declaration and not definition. So for functions prototypes, extern doesn't add any value as it already just a definition. Reference: C Extern
Hope this helps.
The extern keyword is redundant when declaring functions, since it is obvious it has to be defined somewhere else. The same is not true for variables where there would be no difference between a declaration and a definition without extern.
size_t is what strlen is defined to return. In your case it also seems like a 64-bit system, where theoretically a string can be larger that what can be stored in an int.
__cdecl is the calling convetion used when compiling the standard library. In case you should select a different calling convention for your program (using some compiler options), the precompiled library functions will still use the correct convention.
I most often name all the parameters in a function declaration, because it helps document what they are. Just int f(int, int, int, int) doesn't help me much, but is enough for the compiler. Therefore the names are optional.
About size_t as #Rohan said, it a type that used to hold size. it can't be negative for example. It's mainly because of some security issues. ( For example security vulnerability in getpeername in FreeBSD caused by using int instead of size_t )
And about cdecl this might help you ( It's from PC assembly book ) :
Borland and Microsoft use a common syntax to declare calling conventions. They add the cdecl and stdcall keywords to C. These keywords act as function modifiers and appear immediately before the function name in a prototype. For example, the function f would be defined as follows for Borland and Microsoft:
void __cdecl f ( int );
There are advantages and disadvantages to each of the calling conventions. The main advantages of the cdecl convention is that it is simple and very flexible. It can be used for any type of C function and C compiler. Using other conventions can limit the portability of the subroutine. Its main disadvantage is that it can be slower than some of the others and use more memory (since every invocation of the function requires code to remove the
parameters on the stack).
The advantages of the stdcall convention is that it uses less memory
than cdecl. No stack cleanup is required after the CALL instruction. Its main
disadvantage is that it can not be used with functions that have variable
numbers of arguments. [Like printf]
Recently while learning about c programming i noticed something that i found interesting. I had read that a statement like int i=0; is the only way to force a definition while a statement like extern int i; implies a forced declaration. A statement like int i; would be context dependent. But what happens when i combine the the extern with initialization like extern int i=13;. Compiler generates a warning. But what is this rule governing this?
This is a Coding style warning.
The argument for this is the code is valid, but extremely unidiomatic for C since "extern" is generally expected to mean that the declaration is not providing a definition of the object.
extern int i=13;
declares and defines i, While:
extern int i;
just declares the variable i.
A specific bug 45977 has been raised on GCC on the same but it is still shows Unconfirmed Status.
The bug report points out that the code is syntactically as per the C standard. And it has an discussion which discusses this in detail.
For Standerdese Fans:
Relevant Section References are:
ansi c99 Standard 6.2.2: Linkage Of Identifiers and
ansi c99 Standard 6.9.2.4
When you declare a variable you just bind a name to it.
When you define a variable you reserve memory for it.
When you declare a variable as extern you are telling the compiler "this is defined elsewhere and will be available on linking time", so it's OK to use it.
Extern is used if you want to access particular variable from different program. As you don't have any definition for that in you program your complier is giving you an error.
In C, a definition is just a declaration that happens to allocate storage (whether it is because it has an initializer, or because it is a tentative definition that gets used as a definition). So, everything that you can do to a declaration (like specifying it has extern storage), you can also do to a definition.
Note that this differs from C++.