Static function access in other files - c++

Is there any chance that a function defined with static can be accessed outside the file scope?

It depends upon what you mean by "access". Of course, the function cannot be called by name in any other file since it's static in a different file, but you have have a function pointer to it.
$ cat f1.c
/* static */
static int number(void)
{
return 42;
}
/* "global" pointer */
int (*pf)(void);
void initialize(void)
{
pf = number;
}
$ cat f2.c
#include <stdio.h>
extern int (*pf)(void);
extern void initialize(void);
int main(void)
{
initialize();
printf("%d\n", pf());
return 0;
}
$ gcc -ansi -pedantic -W -Wall f1.c f2.c
$ ./a.out
42

It could be called from outside the scope via function pointer.
For example, if you had:
static int transform(int x)
{
return x * 2;
}
typedef int (*FUNC_PTR)(int);
FUNC_PTR get_pointer(void)
{
return transform;
}
then a function outside the scope can call get_pointer() and use the returned function pointer to call transform.

No, unless there's a bug in the compiler. Normally the static function code is not tagged with a name used for exporting the function in the object file, so it is not presented to the linker and it just can't link to it.
This of course only applies to calling the function by name. Other code within the same file can get the function address and pass it into a non-static function in another file and then the function from another file can call your static function.

It cannot be accessed outside a file by it's name. But, you can as well assign it to function pointer and use it wherever you want.

"Accessed"? It depends on what you mean by this term. I assume when you say "static function" you are talking about standalone function declared static (i.e. declared with internal linkage) as opposed to static class member functions in C++, since the latter are obviosly and easily accessible from anywhere.
Now, a standalone function declared static has internal linkage. It cannot be linked to from any other translation unit. Or, putting it differently, it cannot be referred to by name from any other translation unit. If that's what you meant by "access from outside the file scope", then no, it can't be done.
However, if the other translation units somehow get a pointer to that function (i.e. if you somehow allow that pointer to "leak" into the ouside world), then anybody can still call that function by making an idirect call and thus "access" it. For example, if you declare
static void foo_static(void) {
}
extern void (*foo_ptr)(void) = foo_static;
then in any other translation unit the user will be able to do
extern void (*foo_ptr)(void);
foo_ptr();
and the call will go to your foo_static function. I don't know if that kind of access qualifies as "access" in your question.

Following the standard, a static function cannot be accessed outside of the scope of the file by name because it is subject to internal linkage. It's name is not exported, and not provided to the linker. However, it can still be accessed and called by function pointer, like any other function.

Only with trickery. The function is generally not visible to the linker so it won't let you do it.
But, if you provide a function inside the same compilation unit (as the static function) which returns the address of that function:
In main.c:
#inclde <stdio.h>
int (*getGet7(void))(void);
int main (void) {
int (*fn)(void) = getGet7();
printf ("Result is: %d\n", fn());
return 0;
}
In hidden.c:
static int get7 (void) {
return 7;
}
int (*getGet7(void)) (void) {
return get7;
}
This will result in the static function get7 being called.
pax> gcc -o demo main.c hidden.c ; ./demo
Result is: 7

No, the purpose of the keyword static is to limit the scope of the function name to the file.

Related

For a function that takes a const struct, does the compiler not optimize the function body?

I have the following piece of code:
#include <stdio.h>
typedef struct {
bool some_var;
} model_t;
const model_t model = {
true
};
void bla(const model_t *m) {
if (m->some_var) {
printf("Some var is true!\n");
}
else {
printf("Some var is false!\n");
}
}
int main() {
bla(&model);
}
I'd imagine that the compiler has all the information required to eliminate the else clause in the bla() function. The only code path that calls the function comes from main, and it takes in const model_t, so it should be able to figure out that that code path is not being used. However:
With GCC 12.2 we see that the second part is linked in.
If I inline the function this goes away though:
What am I missing here? And is there some way I can make the compiler do some smarter work? This happens in both C and C++ with -O3 and -Os.
The compiler does eliminate the else path in the inlined function in main. You're confusing the global function that is not called anyway and will be discarded by the linker eventually.
If you use the -fwhole-program flag to let the compiler know that no other file is going to be linked, that unused segment is discarded:
[See online]
Additionally, you use static or inline keywords to achieve something similar.
The compiler cannot optimize the else path away as the object file might be linked against any other code. This would be different if the function would be static or you use whole program optimization.
The only code path that calls the function comes from main
GCC can't know that unless you tell it so with -fwhole-program or maybe -flto (link-time optimization). Otherwise it has to assume that some static constructor in another compilation unit could call it. (Including possibly in a shared library, but another .cpp that you link with could do it.) e.g.
// another .cpp
typedef struct { bool some_var; } model_t;
void bla(const model_t *m); // declare the things from the other .cpp
int foo() {
model_t model = {false};
bla(&model);
return 1;
}
int some_global = foo(); // C++ only: non-constant static initializer.
Example on Godbolt with these lines in the same compilation unit as main, showing that it outputs both Some var is false! and then Some var is true!, without having changed the code for main.
ISO C doesn't have easy ways to get init code executed, but GNU C (and GCC specifically) have ways to get code run at startup, not called by main. This works even for shared libraries.
With -fwhole-program, the appropriate optimization would be simply not emitting a definition for it at all, as it's already inlined into the call-site in main. Like with inline (In C++, a promise that any other caller in another compilation unit can see its own definition of the function) or static (private to this compilation unit).
Inside main, it has optimized away the branch after constant propagation. If you ran the program, no branch would actually execute; nothing calls the stand-alone definition of the function.
The stand-alone definition of the function doesn't know that the only possible value for m is &model. If you put that inside the function, then it could optimize like you're expecting.
Only -fPIC would force the compiler to consider the possibility of symbol-interposition so the definition of const model_t model isn't the one that is in effect after (dynamic) linking. But you're compiling code for an executable not a library. (You can disable symbol-interposition for a global variable by giving it "hidden" visibility, __attribute__((visibility("hidden"))), or use -fvisibility=hidden to make that the default).

Trouble with using namespace and static methods

I am trying to write some namespaces statics methods and variables in order to have a set of functions i can use from anywhere in the code. This is what I have:
Header:
namespace CProfileIO
{
static void setAppDir(std::string appDir);
static int reloadProfiles();
static std::string directory;
static std::list<std::string> profilesList;
}
Source:
namespace CProfileIO
{
void setAppDir(std::string appDir)
{
directory = appDir;
}
int reloadProfiles()
{
// ...
}
} // namespace CProfileIO
Then somewhere in the code I have:
#include "CProfileIO.h"
int main(int argc, char * argv[])
{
string appDir = string(dirname(*argv));
CProfileIO::setAppDir(appDir);
.
.
.
}
When I try to compile, i get error at the line I am using the function:
... undefined reference to `CProfileIO::setAppDir(std::string)'
I cant figure out what is wrong. I would aprichiate all help!
You should not use static functions here, as they are visible only in the current translation unit. Thus, you declare a static function which you define (statically) in the cpp, then it won't be visible from other translation units.
You should simply not use the static keyword here, but declare variables (but not functions) as extern.
Also, I recommend to pass the string argument as const reference (void setAppDir(const std::string& appDir);)
That is because static methods are only visible in the current module, (source file). They are not linked.
Hence you other sourcefile doesn't find the function. That is supposed to happen if you use static. I don't know why you would declared naked functions as static, maybe you meant to put them into a class?

Does static function hide non-static function with the same name?

I tried to look this up, but did not find it anywhere. So here's the question:
Static functions in C/C++ can be used to "make them invisible to the outer world". Great, when having two same-named static functions in two different compiled units (.c files), it makes me sure that I call the right one. But can I also be sure that I call my local static function when there exists a same-named non-static function somewhere in the project or libraries? That is, does the static function locally hide the non-static one?
Sure I can test it (and I did) but I want to know whether this behaviour has fixed definition in C/C++. Thanks.
Edit: Simplified example code which caused unexpected behaviour to me. The question is about the fix of the problem (suppose I cannot change the library).
In mylib.c:
#include "mylib.h"
int send(void * data, int size);
...
int send(void * data, int size) {
return send_message(queueA, data, size);
}
void libfunc(void) {
send(str, strlen(str));
}
In mylib.h:
// only libfunc is declared here
void libfunc(void);
In myprog.c:
#include "mylib.h"
int send(void * data, int size);
...
int send(void * data, int size) {
return send_message(queueB, data, size);
}
void progfunc(void) {
// expected to send a message to queueB
// !!! but it was sent to queueA instead !!!
send(str, strlen(str));
}
Compiled mylib.c + further files -> mylib.a
Compiled myprog.c -> myprog.o
Linked myprog.o + mylib.a -> myprog
You'd get a compilation error because functions have default external linkage, thus the new static function would result in a conflict of linkage specifiers.
If the declaration of the non-static function isn't visible, the static one will be called:
void foo(); //external linkage
static void foo() {}; //internal linkage and error
It does not hide functions with same name declared in the same scope. However you may not have a function with the same signature declared as having internal and external linkage.

global const variable definition - access through extern in c++

I read some answers about this topic, but I am still not sure:
In C++ a global const variable definition is automatically static. However I can access it from another cpp-file through extern:
// module.cpp
const int i = 0;
and
// main.cpp
extern const int i;
int main ()
{
if (i > 10)
return 0;
else
return 1;
}
Why is this possible (accessing an object with internal linkage from another module)? Normally I should be forced to define i as extern const int i = 0 in module.cpp, to have an explicitely global but non-static const, or?
In comparison, this is not possible:
// module.cpp
static int i = 0;
and
// main.cpp
extern int i;
int main ()
{
i = 10; // but read-only access like (i > 10) would be possible!
return 0;
}
So is the answer that: yes, you can access internal linked objects from other modules, but only for read (so always with const)?
Edit:
Sorry, but I made a mistake: in my original code I just tried an expression without effect (in both examples):
extern const int i; // or extern int i for second example
int main ()
{
i>10;
return 0;
}
I thought, that it behaves the same, as if program flow or data was dependent of this expression, but in fact it does not! The compiler seems to just cut out this effectless expression, so that the linker does not see it! So all is alright: in the first example i must be indeed defined extern const int i = 0 in module.cpp, and in the second example i cannot be accessed at all (unless in effectless expression). Compiler is VC++2010.
Edit2:
However, now I don't understand why this is possible:
// module.cpp
extern const int i = 0;
and
// main.cpp
int i = 99;
int main ()
{
bool b = i>10;
return 0;
}
i have both external linkage. But no error. When in module.cpp I define int i = 0, then error (multiple symbols). Why?
As for me it looks like a compiler bug. Constant variable i is not defined It is only declared in main.cpp. As for variable i in module.cpp then it has internal linkage and shall not be accessible outside the module.
Relative to your addition to the original post then the compiler has nothing common with this situation. It is linker that checks whether there are duplicate external symbols. I think it decided that if one variable has qualifier const and other has no it then there are two different variables. I think that it is implementation defined whether the linker will issue an error or not. Moreover it can have some options that could control the behaviour of the linker in such situations.

Assign C++ instance method to a global-function-pointer?

Greetings,
My project structure is as follows:
\- base (C static library)
callbacks.h
callbacks.c
paint_node.c
.
.
* libBase.a
\-app (C++ application)
main.cpp
In C library 'base' , I have declared global-function-pointer as:
in singleheader file
callbacks.h
#ifndef CALLBACKS_H_
#define CALLBACKS_H_
extern void (*putPixelCallBack)();
extern void (*putImageCallBack)();
#endif /* CALLBACKS_H_ */
in single C file they are initialized as
callbacks.c
#include "callbacks.h"
void (*putPixelCallBack)();
void (*putImageCallBack)();
Other C files access this callback-functions as:
paint_node.c
#include "callbacks.h"
void paint_node(node *node,int index){
//Call callbackfunction
.
.
putPixelCallBack(node->x,node->y,index);
}
I compile these C files and generate a static library 'libBase.a'
Then in C++ application,
I want to assign C++ instance method to this global function-pointer:
I did something like follows :
in Sacm.cpp file
#include "Sacm.h"
extern void (*putPixelCallBack)();
extern void (*putImageCallBack)();
void Sacm::doDetection()
{
putPixelCallBack=(void(*)())&paintPixel;
//call somefunctions in 'libBase' C library
}
void Sacm::paintPixel(int x,int y,int index)
{
qpainter.begin(this);
qpainter.drawPoint(x,y);
qpainter.end();
}
But when compiling it gives the error:
sacmtest.cpp: In member function ‘void
Sacm::doDetection()’:
sacmtest.cpp:113: error: ISO C++
forbids taking the address of an
unqualified or parenthesized
non-static member function to form a
pointer to member function. Say
‘&Sacm::paintPixel’ sacmtest.cpp:113:
error: converting from ‘void
(Sacm::)(int, int, int)’ to ‘void
()()’
Any tips?
This is answered in the C++ FAQ, [1]. This doesn't work, because the pointer isn't associated with a particular object instance. The solution is given there too, create a global function that uses a particular object:
Sacm* sacm_global;
void sacm_global_paintPixel(int x,int y,int index)
{
sacm_global->paintPixel(x, y, index);
}
void Sacm::doDetection()
{
putPixelCallBack = &sacm_global_paintPixel;
//call somefunctions in 'libBase' C library
}
You have to somehow setup the global variable properly.
You cannot convert an instance method pointer to a normal function pointer. A workaround is to use another global variable to hold the instance and a global wrapper function that is used as the callback and then in turn calls the instance method:
Sacm *callbackSacm;
extern "C" // since it sounds like it's called from a C library
void call_paintPixel(int x, int y, int index) {
callbackSacm->paintPixel(x, y, index);
}
void Sacm::doDetection() {
callbackSacm = this;
putPixelCallBack = call_paintPixel;
}
You can alternatively use a static member function. The address of a static member function can be taken and assigned to a regular function pointer, because no this pointer is implicitly passed to it -- under the hood, these functions operate just like regular non-member functions. But they have advantages over non-member functions:
A static method still has access to the private and protected members of any object of its class type.
A static method can be private or protected so access to it can be controlled.
Using a static method lets you and group functionality inside the class, where it belongs.