For C99, is the following syntax legal when splitting up static inline functions into separate declarations and definitions?
foo.h:
#include "foo_decl.h"
#include "foo_def.h"
foo_decl.h:
#ifndef _FOO_DECL_H
#define _FOO_DECL_H
/* Here we document foo */
inline int foo(int x);
/* Here we document bar */
inline int bar(int x, int y);
#endif // _FOO_DECL_H
foo_def.h:
#ifndef _FOO_DEF_H
#define _FOO_DEF_H
inline static int foo(int x) { return x+3; }
inline static int bar(int x, int y) { return x-y+22; }
#endif // _FOO_DEF_H
The declaration is really useless to the compiler, but it serves a purpose for collecting documentation for functions in one place without getting cluttered by interspersed implementation details.
Or should foo_decl.h include the static keyword?
This is undefined behaviour according to 6.2.2/7:
If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
The line inline int foo(int x); declares foo to have external linkage (6.2.2/5), but static int foo(int x) { declares foo to have internal linkage.
If you really want to do this then the versions in foo_decl.h and foo_def.h must either both have static, or neither have static. In the latter case exactly one .c file must have extern inline int foo(int x);.
Related
I am trying to 'gather' global cmdOps spread in multiple files into lookup table for convenient usage in main. I did as shown below, but as pointed out this approach does not guarantee file1.c and file2.c to use the same variables, but I really want to avoid using extern declarations in file1.c as there will be tens of them if not more.
main.c:
#include "file1.h"
int getLutIdx(int argc, char *argv[]);
extern myLUT *LUT;
int main(int argc, char *argv[])
{
int idx = getLutIdx(argc, argv);
myArgs args;
LUT[idx].ops->parseArgs(argc, argv, &args);
LUT[idx].ops->validateArgs(&args);
LUT[idx].ops->executeCmd(&args);
}
file1.h:
typedef struct myArgs {
union {
cmd1Args_t cmd1Args;
cmd2Args_t cmd2Args;
...
}
}myArgs;
typedef int (*op1)(int argc, char *argv[], myArgs *args);
typedef int (*op2)(myArgs *args);
typedef int (*op3)(myArgs *args);
typedef struct cmdOps {
op1 parseArgs;
op2 validateArgs;
op3 executeCmd;
} cmdOps;
typedef struct myLUT {
char *cmdName;
cmdOps *ops;
}myLUT;
file1.c:
#include "file1.h"
#include "file2.h"
#include "file3.h"
myLUT LUT[CMD_NUM] {
{ "CMD1", &cmd1Ops },
{ "CMD2", &cmd2Ops },
...
}
file2.h:
int cmd1ParseArgs(int argc, char *argv[], myArgs *args);
int cmd1ValidateArgs(myArgs *args);
int cmd1Execute(myArgs *args);
int cmd2ParseArgs(int argc, char *argv[], myArgs *args);
int cmd2ValidateArgs(myArgs *args);
int cmd2Execute(myArgs *args);
cmdOps cmd1Ops;
cmdOps cmd2Ops;
file2.c
#include "file1.h"
#include "file2.h"
myOps cmd1Ops = {
.parseArgs= cmd1ParseArgs,
.validateArgs = cmd1ValidateArgs,
.executeCmd = cmd1Execute
}
myOps cmd2Ops = {
.parseArgs= cmd2ParseArgs,
.validateArgs = cmd2ValidateArgs,
.executeCmd = cmd2Execute
}
...
Whole question edited, thanks for previous comments.
Goal is for user to invoke:
./myProg <cmd_name> <cmd_args>
and each command (or sets of commands) can accept different parameters
The "best way" would be to not have any global variables (or at least, as few as possible), since global variables are likely to make your program difficult to understand and debug as it gets larger and more complex.
If you must have global variables, however, I suggest declaring the global variables in just one .c file:
myOps file2Ops; // in somefile.c
... and placing any necessary extern declarations in a .h file that other files can include:
extern myOps file2Ops; // in someheader.h
But it baffles me why don't I get any error or warning about duplicated declaration…
At file scope, myOps file2Ops; is a tentative definition, which is not actually a definition, directly. If there is no definition for it by the end of the translation unit, the behavior is as if there were a definition myOps file20ps = {0};. (Having an initializer would make the declaration a proper definition instead of a tentative definition.)
Then, because myOps file20ps; appears in file2.h and that is included in both file1.c and file2.c, your program has multiple external definitions of file20ps. The C standard does not define the behavior of this because it violates the constraint in C 2018 6.9 5:
… If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.
Historically, some C implementations have defined the behavior of external identifiers resulting from tentative definitions to act as “common” symbols. When linking the object modules, a definition originating from a tentative definition will be coalesced with other definitions, so there will be only one definition in the final program. Your C implementation (notably the compiler and the linker) appears to be doing this, and that would be why you did not get an error message.
(This was the default behavior for GCC prior to version 10. You can request the old behavior with -fcommon or the non-coalescing behavior with -fno-common. Some additional information is here and here.)
… and I also don't know if this approach would be considered 'good practice'
You have not shown much context for what you are doing or why. Generally, external identifiers for objects should be avoided, but there can be appropriate uses.
I know that there are multiple ways to accomplish this, i.e static could be used on both the declaration and the definition OR it could only be used on the declaration.
Is this the common way of doing so?
// `static` on both the declaration and definition.
static void f1();
static void f1(){}
// `extern` on only the declaration (shared header file).
// then define in a single source file.
extern void f2();
void f2(){}
// `inline` usually doesn't need a declaration, just define it in a shared header file.
inline int f3(){}
int main(){
return 0;
}
in my university our teacher taught us "we define function prototype before main function. Like:
#include<stdio.h>
void findmax(float, float);
int main()
{
//code goes here
}
But today my friend showed me they learned they put prototype inside main function. Like:
#include<stdio.h>
int main()
{
void findmax(float, float);
float firstnum, secondnum;
printf("Enter first:");
scanf("%f", &firstnum);
printf("Enter second:");
scanf("%f", &secondnum);
findmax(firstnum, secondnum);
}
void findmax(float x, float y)
{
float maxnum;
if(x>y)
{
maxnum=x;
}
else
{
maxnum=y;
}
printf("The max is %f", maxnum);
}
They both works.I wonder if there are differences between them. Thanks.
Can we define function prototype in main function in C?
Yes.
I wonder if there are differences between them
The difference is that in first snippet prototype is global while in second it is local to main. findmax will be visible after its declaration and/or definition.
#include<stdio.h>
void foo();
int main()
{
void findmax(float, float);
foo();
findmax(10, 20); // It knows findmax by the prototype declared above
}
void findmax(float x, float y)
{
float maxnum;
if(x>y)
maxnum=x;
else
maxnum=y;
printf("The max is %f", maxnum);
}
void foo(){ // foo is using findmax after its definition.
findmax(12, 30);
}
If foo is declared in outside a function, it can be called from any function in the same file:
void foo(); // <-- global declaration
int main() {
foo(); // <-- works, foo() is declared globally
}
void otherfunc() {
foo(); // <-- works, foo() is declared globally
}
However, if foo is declared inside a function, it can only be used within the same scope:
int main() {
void foo(); // <-- scoped declaration
foo(); // works, foo() is declared in same scope
}
void otherfunc() {
foo(); // ERROR: foo() is not declared in scope of otherfunc()
}
In either case, foo must be declared before it is used.
If you declare the function in main() it is scoped in the main() and you cannot access it in another function. But if you declare it at the start of the file or in a header file you can use it in any function.
A straightforward answer to your question would simply be a YES. But when it comes to the scope, I'd like to add more.
What others suggest is right -- if you declare a function inside another function, the first one's scope is usually limited to the second one. For the example you provided, it is perfectly safe to say so. But that may not be the case always. Consider the following code:
#include <stdio.h>
/* Can be accessed from anywhere in this file
* because defined before anything else.
*/
void print_hello() {
puts("Hello!");
}
int main() {
void print_hello(); /* Not needed actually */
void print_namaste();
void print_hi();
print_namaste();
print_hi();
}
/* The following two functions cannot be
* accessed from within the above two functions
* unless these two are declared inside them
* or at the starting of this file
*/
void print_namaste() {
puts("Namaste!");
print_hello();
}
void print_hi() {
puts("Hi!");
}
Here you can see that print_hello() is declared inside main(). But that is redundant. print_hello() has already been introduced into the compiler. There is no need of declaration to use it inside this file (if you use it inside other files and compile them independently, then you'll have to declare it inside those files or write a header file to do so). What my point is, declaring print_hello() inside main() has not rendered it local, at least in this example. You can see print_namaste() calling it successfully without any additional declaration.
But that is not the case with print_namaste() and print_hi(). They require declaration to be used from within main() because they are introduced to the compiler only after main() has been defined.
print_namaste() will only be visible to the functions inside which we declare it, and to those functions which are defined after print_namaste(). In this example, print_namaste() is not visible to print_hello() (unless declared inside it or before it), but visible to main() because declared inside it, and visible to print_hi because its definition comes only after the definition of print_namaste().
In VC2008 the following is valid:
int main(void)
{
void foo(void);
//...
}
void test(void)
{
foo();
}
My believe was that prototype declarations are valid anywhere and their scope is at least from the point of declaration to the end of file.
Looking at the C99 standard:
6.2.1 Scope of Identifiers
An identifier can denote an object; a function; a tag or a member of a structure, union, or
enumeration; a typedef name; a label name; a macro name; or a macro parameter... For each different entity that an identifier designates, the identifier is visible (i.e., can be
used) only within a region of program text called its scope... identifier has scope determined by the placement of its declaration (in a
declarator or type specifier). If the declarator or type specifier that declares the identifier
appears outside of any block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit. If the declarator or type specifier that
declares the identifier appears inside a block or within the list of parameter declarations in
a function definition, the identifier has block scope, which terminates at the end of the
associated block.
This would mean that VC2008 is wrong.
I'm trying to pass a local variable (in func1) to a function (func2) in another file, but func2 requires that as a global variable. To explain things better, here are the two files:
file1.c:
#include <something.h>
extern void func2();
void func1(){
int a=0;
func2();
}
file2.c:
#include <something.h>
extern int a; //this will fail
void func2(){
printf("%d\n",a);
}
The variable int a can't be declared as global in file1, as func1 is called recursively. Is there a better way to do this?
In file1.c:
#include <something.h>
#include "file1.h"
int a;
void func1(){
a = 0;
}
In file1.h
extern int a;
In file2.c:
#include <something.h>
#include "file1.h"
void func2(){
printf("%d\n",a);
}
So:
The variable is in file1.c
file1.h allows others to know that it exists and its type is int.
file2.c includes file1.h so that the compiler knows about var a existence before file2.c tries to use it.
Sorry I can’t comment on Ciro Pedrini’s answer, so I would say: do as he says, but also:
Make the argument list of func1 explicitly (void) (and set your compiler to complain about empty argument lists), because () just means you are not specifying what the arguments are, at least in C, which your question is tagged as.
Declare void func1(void); as well as a in file1.h.
#include file1.h in file1.c, so the compiler checks that the definitions (in file1.c) of a and func1 are consistent with their declarations (in file1.h).
But, although you may have to do this as an exercise, try to avoid passing information in global variables: arguments are usually more reliable, as it is easier to ensure that no other part of the programme alters them. And you talk about passing information to a recursive function through a global variable: in that case you must be especially careful to pick up and save the value in func1 before a recursive call alters the value - passing an argument is so much easier and more reliable!
Ciro's solution would have worked if I am only using func1 once; however func1 is called recursively so variable a cannot be global in file1 (i.e. the variable has to live on the stack and not on the heap). Here's the solution I ended up using:
File1.c:
#include <something.h>
extern void func2_new(int b);
void func1(){
int a=0;
func2_new(a);
}
File2.c:
#include <something.h>
int a;
void func2(){
printf("%d\n",a);
}
void func2_new(int b){
a=b;
func2();
}
As many have pointed out, the only answer would be to refactor func2 completely. I welcome more input to this solution.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I share variables between different .c files?
If I have two source files, and one header: file1.c, file2.c, and header.h, and:
--header.h--
int i;
--file1.c--
#include <header.h>
i = 10;
int main() {
func();
return 0;
}
--file2.c--
#include <header.h>
void func() {
printf("i = %d\n", i);
return;
}
I get the warning that i defaults to an int. What could I do if I want to have i as a float for instance?
Make it
extern int i;
in the header and
int i = 10;
in file1.c.
The warning means that for the (incomplete) declaration i = 10; in file1.c, the "implicit int" rule is applied, in particular, that line is interpreted as a declaration (since an assignment cannot appear outside function scope).
You have a couple of errors in your code. The first is that you define the variable i in the header file, which means that it will be defined in all source files that include the header. Instead you should declare the variable as extern:
extern int i;
The other problem is that you can't just assign to variables in the global scope in file1.c. Instead it's there that you should define the variable:
int i = 10;
Declare it as extern in the header (this means memory for it is reserved somewhere else):
/* header.h */
extern int i;
Then define it in only one .c file, i.e. actually reserve memory for it:
/* file1.c */
int i = <initial value>;
In the header use
extern int i;
in either file1.c or file2.c have
int i = 20;
If you want float just change int to float
In 99.9% of all cases it is bad program design to share non-constant, global variables between files. There are very few cases when you actually need to do this: they are so rare that I cannot come up with any valid cases. Declarations of hardware registers perhaps.
In most of the cases, you should either use (possibly inlined) setter/getter functions ("public"), static variables at file scope ("private"), or incomplete type implementations ("private") instead.
In those few rare cases when you need to share a variable between files, do like this:
// file.h
extern int my_var;
// file.c
#include "file.h"
int my_var = something;
// main.c
#include "file.h"
use(my_var);
Never put any form of variable definition in a h-file.