Two questions regarding static keyword in C - c

I have this snippet of code:
int foo1(void); //line a
int foo2(void) {
return foo1();
}
int foo1(void) { //line b
return 99;
}
If I want to declare function foo1 to be static, should I put the keyword static in line a or line b? Is there any difference?
Also say I have the following code in ANOTHER file that uses foo1 in the above file:
static int foo1(void);
int main(void) {
return foo1();
}
The code still compiles and works as expected although I put static in the declaration line. But it gives a warning saying that 'foo1' used but never defined - if it's not defined, why does the code still work?
Edit:
Sorry I didn't make that clear, for the second question, foo1 in the first file where it's defined is not declared as static, but I declare it as static in the second file.

In the first case, you need to put static on both line a and b. Static functions in C has internal linkage meaning that they are only visible in the same file. So for declaration and definition, you need to put static so that compiler knows that the function has internal linkage. If you don't put static on line a, you will get some compilation errors.
In the second case, since foo1 is a static function, it must be defined in the same file as main. You only put a forward declaration without actual definition. Even though it compiles fine, the program will not link since foo1 is not defined.

The static keyword in this context specifies that foo1 not be exported, so that particular foo1 could only be defined in that same compilation module, hence the warning when it isn't. (Without the static the code would be correct, assuming you mean to link the foo1 from the other file.)
As for why it works regardless of this, my guess is that the compiler falls back on looking for the external function, which it finds from your other file, but I think a conforming compiler would be justified in giving an error here.

In C static for functions means internal linkage and use of the function only within the scope of the file.
Interesting that compilers behave differently:
Snippet 1:
GCC and clang requires putting static in declaration (line a), in definition (line b) it can b omitted then.
In MS VC you can put static in declaration or in definition only, this makes foo1() static.
Snippet 2 (static foo1 in main.c, non-static declaration in other file):
GCC compiles static declaration without definition. clang compiles but outs a warning. (Both link then.)
MS VS does not compile the second snippet at all, giving an error C2129.
So, put static in both declaration and definition for clarity, and define static functions in the files where they are declared. Put forward declarations if required before usage of the functions.
Overall, seems that clang has better diagnostics.
"...if it's not defined, why does the code still work?"
In C it is not required to declare prototype before function call. The definition is than found on the linkage step.

Related

Static function was declared but never referenced error

For the following code in C:
file.h
// declaration of extern function
extern void extFunc();
file.c
#include "file.h"
// declaration of static function
static void localFunc(uint32_t const input);
// definition of static function
void localFunc(uint32_t const input)
{
// do something
}
// definition of extern function
void extFunc()
{
// do something
}
When I compile the above code for ARM ISA target, I get compiler error saying
Error[Pe177]: function "localFunc" was declared but never referenced in C:\Users\admin\git\file.c
How to get rid of it ?
Error[Pe177]: function "localFunc" was declared but never referenced in C:\Users\admin\git\file.c
How to get rid of it ?
localFunc() is declared static. This means that the version of that function appearing in file.c is not accessible by name from other translation units. Your compiler is telling you that it is not accessed by name from the same translation unit either, and no pointer by which it could be called is exposed, so the function definitely is not called at all. It is dead code.
Normally this kind of issue warrants a warning instead of an error, but perhaps your compiler is especially strict, or you have enabled an option turns warnings into errors, so as to force you to resolve all diagnostics that otherwise would be just warnings. In any event, there are several possible solutions, but these are the most likely:
Delete localFunc() and its forward declaration from file.c, or comment them out, or suppress them via conditional compilation directives. This assumes that it is intentional that they are going unused.
Insert live code that calls localFunc(). This only makes sense if it was some kind of mistake that localFunc() was not being called within the translation unit already.

Get value of static variables in inline functions?

May be my question is a little bit silly, but I can't get this code to work correctly. I have read similar question with answers, but there were a little bit different situation.
So, the question is: "Is it possible to get static variable value in inline functions?"
I code the program for microcontroller with small amount of memory and low speed. For some reason I need to make some functions inline (to save memory and time of execution).
This is the problem description:
For example, I have three files in my program: main.c, some.h, some.c .
In some.c:
#include "some.h"
static int foo;
[... other functions that uses "foo"]
In some.h:
#ifndef SOME_H_
#define SOME_H_
static int foo;
inline int __attribute__((always_inline))
get_foo(void){
return foo;
}
#endif
In main.c:
#include "some.h"
int bar;
int main(void){
bar = get_foo();
return bar;
}
When I tried to compile, I'm getting following:
warning: 'foo' is static but used in inline function 'get_foo' which is not static
When I tried to put extern static int foo; to some.h, I got:
error: multiple storage classes in declaration specifiers
error: static declaration of 'foo' follows non-static declaration
I need to get values of "static" variables from external file in "inline" functions. I want to keep them "static" to separate from main code, as local variable. Is it a way to do this correctly?
Thank you in advance!
EDIT:
To be more clear: I need to get the the value of a variable in one file (some.c) in another file (main.c) by inline function. If the function get_foo() is NOT "inline", everything works perfect, but it takes more memory and execution time.
In this case, static means the variable foo will be a different foo in each source file. If you change static int foo; to extern int foo; in the header and then have a single int foo; in one .c file, I think the compiler warning will go away and your inline function will work fine.
At file scope, static hides a name from the linker so you effectively have different variables in each file.
extern static int foo; is just a mistake. It means, there is something called foo in some other file that I want you to link to, but the name is hidden. The compiler is just saying "forget it".
There is no point for defining a static variable in a header file. Every time you include that header file you will get a new fresh copy of the variable...
Why you don't just define it as
extern int foo;
This way you will have the variable available from any source that included the header
Your request for inlining is in some way incompatible with the internal linkage of the variable.
You have a static variable which means that this variable is only visible in that file.
On the other you have an inline function. If this function would be inlined somewhere else than in this file, then it would refer to another foo variable, which is probably not what you want; at least the compiler warns you about it. It suggests you to change the visibility of that function to static, as to only be available in the same entity than foo.
In another try, you add extern, but this is incompatible with static visibility, choose, extern or static. Read about linkage and visibility rules in C language, for more information.
You also suggest to add foo in some header, which is not a good idea, headers are reserved for declaration of objects not definition. You are encouraged to add type definition in headers, external declaration of objects; but discouraged from define objects (while not strictly forbidden, this would too often lead to clashes).
If you want to have your variable static in a specific translation unit, an inline function that would "live" in another translation unit would never be able to access this static object. That is why access to static objects from inline functions is not allowed, the semantics of what that would mean is simply not clear.
You can either define an extern function that provides the value of its TU where it is defined, or static function(s) with different instantiations in every TU that provide just the value, there.

if global variable have default external linkage then why can't we access it directly in another file?

I have gone through following questions:
Global variable in C are static or not?
Are the global variables extern by default or it is equivalent to declaring variable with extern in global?
Above links describe that if we define global variable in one file and haven't specified extern keyword they will be accessible in another source file because of translation unit.
Now I have file1.c in that have defined following global variable and function:
int testVariable;
void testFunction()
{
printf ("Value of testVariable %d \n", testVariable);
}
In file2.c have following code
void main()
{
testVariable = 40;
testFunction();
}
Now I am getting error: 'testVariable' undeclared (first use in this function) -- why?
Note: both files are used in same program using makefile.
As per my understanding both function and global variable have default external linkage. So function we can use directly by it's name in another file but variable can't why?
Can any one have idea?
EDIT:
From the below answer i get idea that like in case of function old compiler will guess and add an implicit declaration but in case of variable it can't. Also C99 removed implicit declaration but still I am getting warning in C99 mode like:
warning: implicit declaration of function ‘testFunction’.
Now have gone through below link:
implicit int and implicit declaration of functions with gcc compiler
It said that compiler take it as diagnostic purpose and not give error. So compiler can process forward.
But why in case of variable it can't process further? Even in case of function if compiler proceed and if actual definition not there then at linking time it will fail. So what's benefit to move forward??
There are two things in play here: The first is that there is a difference between a definition and a declaration. The other thing is the concept of translation units.
A definition is what defines the variable, it's the actual place the variable exists, where the compiler reserves space for the variable.
A declaration is needed for the compiler to know that a symbol exists somewhere in the program. Without a declaration the compiler will not know that a symbol exists.
A translation unit is basically and very simplified the source file plus all its included header files. An object file is a single translation unit, and the linker takes all translation units to create the final program.
Now, a program can only have a single definition, for example a global variable may only exist in a single translation unit, or you will get multiple definition errors when linking. A declaration on the other hand can exist in any number of translation units, the compiler will use it to tell the linker that the translation references a definition in another (unknown at time of compilation) translation unit.
So what happens here is that you have a definition and a declaration in file1.c. This source file is used as input for one translation unit and the compiler generates a single object file for it, say file1.o. In the other source file, file2.c, there is no definition nor any declaration of the global variable testVariable, so the compiler doesn't know it exists and will give you an error for it. You need to declare it, for example by doing
extern int testVariable; // This is a declaration of the variable
It's a little more complicated for the function, because in older versions of the C standard one didn't have to declare functions being used, the compiler would guess and add an implicit declaration. If the definition and the implicit declaration doesn't match it will lead to undefined behavior, which is why implicit function declarations was removed in the C99 standard. So you should really declare the function too:
void testFunction(void); // Declare a function prototype
Note that the extern keyword is not needed here, because the compiler can automatically tell that it's a function prototype declaration.
The complete file2.c should then look like
extern int testVariable; // This is a declaration of the variable
void testFunction(void); // Declare a function prototype
void main()
{
testVariable = 40;
testFunction();
}
When compiler copes with file2.c it knows nothing about existence of testVariable and about its type. And as result it can't generate code to interact with such object. And purpose of line like
extern int testVariable;
is to let compiler to know that somewhere such object exists and has type of int.
With functions we have no such problem because of next rule - if function is not defined - compiler assumes that it is defined somewhere like
int testFunction() { ... }
So you can pass any number of any arguments to it and try to obtain int return value. But if real function signature differs - you'll get an undefined behafiour at runtime. Because of this weakness such approach is considered as bad practice, and you should declare proper function prototype before any call to that func.

Scope of a function when defined within another function

What will happen when a function defined within another function? What is the difference between code 1 and code 2?
CODE 1:
#include<stdio.h>
void m();
void main()
{
m();
void m()
{
printf("hi");
}
}
CODE 2:
#include <stdio.h>
void m();
void main()
{
void m()
{
printf("hi");
}
m();
}
When I compiled code 1 in gcc compiler, I got linkage error. But when I compiled code 2, I didn't get any error. I got output "hi". I want to know how compilation is done, when we write function definition within another function. I know that when we write function definitions not within another function, wherever be the function definition, we will not get any error when we call that function. for example see the below code:
CODE 3:
#include <stdio.h>
void m();
void main()
{
m();
}
void m()
{
printf("hi");
}
In code 3,even though I called the function before definition, it didn't show any error and I got output. Why it is not happening with code 1.
Neither C nor C++ allows to define a function within another function. So it seems you are using a special language extension of compiler GCC that allows to define local functions inside another functions.
In the first program function m is declared in file scope. So its definition will be searched by the compiler in the file scope. When the function is called inside main only this file scope declaration is visible. However the compiler did not find its file scope definition so it issued an error.
In the second program there is also a declaration of function m in the file scope. However inside function main there is another declaration of function m that has block scope and hides the declaration with the file scope. Take into account that a definition also is a declaration. So the call of m refers to the function m that is declared inside main and has block scope. The compiler has the function definition and can call it.
in the third program that satisfies the C Standard inside main the call of m refers to the function m declared in the file scope and there is a definition of this function in the file scope. So there is no any problem.
You can not define functions inside function. It is not allowed in C and thus won't compile. Code snippet 1 and 2 are invalid and only snippet 3 is valid ANSI C code.
Why code 1 does not compile and code 2 compiles well in gcc
Code 2 compiles under gcc because of a GNU compiler extension. You must declare the function before first usage for this extension to work.
Then why does code 3 compiles
In Snippet 3, you are declaring the function before first usage which is enough for compiler to place the required code. At linking time, required linking with the definition code is required. There is no necessity from linker about the placing of definition (In ISO C specifcations), the function definition is allowed to present even in a separate compilation unit.
It's a scope problem. In your CODE 1 sample, the m function is only visible within the main function. So the function header you put before the main (void m();) expect a global m function and did not find it, that's why you have a link error. In your code 2 sample, the m function is found because it's written before the call, your global m function is still not present but not used => you don't have the link error. In your code 3 sample, your m function is global and then found as expected by the header => no error
In code 3, even though I called the function before definition, it didn't show any error and I got output. Why it is not happening with code 1?
Code 3 is conforming standard C code. A function with external linkage can be called wherever a declaration is visible (provided a definition exists somewhere in the programme, it doesn't have to be in the same file).
When I compiled code 1 in gcc compiler, I got a linkage error.
Nested functions are a GCC extension:
A nested function always has no linkage. Declaring one with extern or static is erroneous. If you need to declare the nested function before its definition, use auto (which is otherwise meaningless for function declarations).
At the point m is called, an external declaration (the file scope declaration void m();) is visible. As there is no external definition in this source file, gcc assumes it is in another translation unit, and eventually the linker fails finding it. According to the quoted documentation, a valid version could be
#include <stdio.h>
int main(void)
{
auto void m(); /* Hides the outer declaration. */
m(); /* Refers to the nested function, not to an external one now. */
void m()
{
printf("hi");
}
}
But when I compiled code 2, I didn't get any error. I got output "hi".
At the point, where m is called, the nested function is visible, hiding the file-scope declaration. The file-scope declaration (declaring a function with external linkage) is never used, so the linker doesn't try to resolve a call to it.
A conforming implementation may accept a declaration of main as a function returning void, but doesn't have to. Old-style (or K&R-style) declarations and definitions are obsolescent in C89, C99 and C11, so it's better to use
int main(void);
void m(void);
Check the link below:
Nested function in C
C doesn't support nested functions so your Code Snippet 1 and 2 are not allowed standards though you might see code snippet 2 working because you have function call after function definition.
The only allowed snippet is Code 3 the rest should not be done in C .
GCC special extensions:
https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
You are not compiling your code as standard C. GCC is tricky because it comes with crappy non-standard settings by default. To use GCC as a proper C compiler, you must do gcc -std=c11 -pedantic-errors, where c11 is the preferred standard (switch to c99 if you have an old version of GCC). While you are at it, ensure to enable all warnings too:
gcc -std=c99 -pedantic-errors -Wall -Wextra
Now that the compiler is configured to be a C compiler, we get the following errors:
CODE1 and CODE2:
error: return type of 'main' is not 'int' [-Wmain].
This error comes because when GCC is set to be a C compiler, it is not providing an implementation-defined way to specify main. You have to change main to int main (void).
error: ISO C forbids nested functions [-Wpedantic]
This error comes because nested functions aren't allowed by the C standard. You got away with it before, because you had GCC set to be a non-standard compiler.

C Cross compiler links extern declared as static?

I'm experiencing some weird behaviour (well, i guess it's got an explanation) while trying to cross compile some Files from Debian to an arm-linux target, using:
$ arm-linux-gnueabi-gcc --version
$ arm-linux-gnueabi-gcc (Debian 4.3.5-4) 4.3.5
While compiling I get these error messages:
dsblock1.c:167: error: non-static declaration of ‘HaveEventIterated_’ follows static declaration
ss2dym.c:778: error: previous declaration of ‘HaveEventIterated_’ was here
The corresponding Lines are:
ss2dym.c:778 :
extern long HaveEventIterated_;
"redeclaration" dsblock1.c:167:
long HaveEventIterated_=0;
So here's the thing i don't get:
according to what i thought i knew, variables first declared extern, are non-statics.
BUT: the "extern" declaration is inside a static function.
So my guess is, that this is some kind of inherited behaviour?!
So here are the questions:
- can someone explain the background story, IF my guess is correct?
- is there an easy way to get around that, e.g. with a tricky compiler-flag that allows nested scope-shifting or some other magic?
I know it would most likely possible to create a header and put all those extern declarations into neutral space, but i've got like hundreds of those errors and several files. And i've seen that this code compiles well using MSVC++ (that has other scope constraints, i know, but i have a lot more problems using arm-g++) so there must be some kind of solution, easier than just rewriting all those parts...
BTW: there is an easy way to change the scope of all those "redeclarations" since i have a macro in front of all of them like:
MY_MACRO long HaveEventIterated_=0;
and atm i compile with -DMY_MACRO=
Soooo anyone? :)
The extern keyword gives identifiers the same linkage1 as a previous visible declaration, or external linkage if there is no previous visible declaration. (This is a weird quirk of the language, to be sure.)
Thus, the problem is most likely occurring due to a third (or perhaps I should say "first") declaration of HaveEventIterated_, that the compiler is reaching before it reaches line 778 of ss2dym.c. That third (or first) declaration uses the static keyword to give the identifier internal linkage. The second declaration, with extern, then gives the same variable internal linkage, and the third—with no storage-class keyword to specify linkage—gives the variable external linkage, resulting in the error.
Here's a short example that reproduces the issue (in a different gcc, but the same behavior):
$ cat foo2.c
static int var;
extern int var;
int var = 0;
$ gcc -c foo2.c
foo2.c:3: error: non-static declaration of 'var' follows static declaration
foo2.c:2: error: previous declaration of 'var' was here
1Side note: if the previous visible declaration has no linkage, you get external linkage. This only occurs when re-declaring a variable inside a block where the variable outside that block has automatic duration, i.e., is a "local" or "stack" variable inside a function:
void f(void) {
int v;
{
extern int v;
Here there's a previous visible declaration with no linkage, so the innermost v has external linkage. If there is a v with internal linkage in the same translation unit, the effect is undefined. (Of course no one should write code like f() in the first place, anyway :-) )

Resources