2

In my C code I want to expose static variables through inline functions , and this way avoid using 'extern' attribute, kind of OOP in standard C. However I cant compile it. Consider the following code:

$ cat object.h
inline int get_value(int index);
$ cat object.c
#include "object.h"
static int data_array[32];

inline int get_value(int index) {
    return data_array[index];
}
$ cat app.c 
#include "object.h"
void main(void) {
    int datum;

    datum=get_value(8);
}
$ gcc -c object.c
object.c:5:9: warning: ‘data_array’ is static but used in inline function ‘get_value’ which is not static
  return data_array[index];
         ^
$ ls -l object.o
-rw-rw-r-- 1 niko niko 976 Aug 30 15:56 object.o
$ gcc -c app.c
In file included from app.c:1:0:
object.h:1:12: warning: inline function ‘get_value’ declared but never defined
 inline int get_value(int index);
            ^
$ ls -l app.o
-rw-rw-r-- 1 niko niko 1368 Aug 30 15:56 app.o
$ gcc -o app app.o object.o
app.o: In function `main':
app.c:(.text+0xe): undefined reference to `get_value'
collect2: error: ld returned 1 exit status

Is it possible to access static variables somehow outside the file they have been declared through an inline function, that would be inlined in every .c file it is being used? Of course I can just declare the variable 'extern':

extern int data_array[];

and reference it directly but I want to do it through a function to simulate OOP in C without the overhead of a function call.

Joseph Quinsey
  • 9,553
  • 10
  • 54
  • 77
Nulik
  • 6,748
  • 10
  • 60
  • 129
  • 4
    C11 draft standard n1570: *6.7.4 Function specifiers 3 An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage.* – EOF Aug 30 '16 at 21:05
  • @EOF too bad... I wonder how does people simulate OOP in C through inline functions ? the only viable alternative would be macros, I guess ... – Nulik Aug 30 '16 at 21:36
  • I don't see how a macro would help in any way. I'm not sure why you insist on the functions being inline though. – EOF Aug 30 '16 at 21:38
  • @EOF I want it to be inlined because I don't want the overhead of a CALL , PUSH, POP and RET instructions. So, an inline function that gets a variable declared in the scope of another file will be just a MOV instruction. That's what I want. Yes, declaring variables as static will not allow macros in any file to access them, but if I declare them as global and use 'extern' that would simulate basic OOP get/set methods. – Nulik Aug 30 '16 at 21:43
  • 1
    That's not what `inline` means ... – Daniel Jour Aug 30 '16 at 22:38
  • 1
    In one file, do `int data_array[32]` and in the (e.g.) `data.h` file do: `extern int data_array[];` and put your inline `get_array` function there, too. Also, add a _comment_ telling people to _only_ access the array via `get_array`. If they violate that, it's _their_ code that will break. I don't believe in "information hiding". Many style guides consider it bad practice. What you're trying to do is, well, just a little "too cute". C isn't a supermax prison. It's a programming language and we use the "honor system" – Craig Estey Aug 30 '16 at 22:38
  • @CraigEstey , yes that's what I will have to do. I just thought "maybe there is a feature in C that would allow me to expose static to the outside somehow" . Like those GCC extensions, which will add their own powerful features to the language, you know .... – Nulik Aug 30 '16 at 22:49
  • 1
    You gotta pick your battles. I've used libraries with static variables. The author assumed that a [legit] user of the lib wouldn't need access. But, that is choice is often just a [wishful] guess. The lib user is up the creek, if _their_ usage needs access because they legitimately do something the lib author didn't anticipate. I use static sparingly. So, instead of `static int value`, to avoid collision with that common name, I use `int mylib_value` and all globals are mylib_* It also helps with `vi \`grep -lr mylib_value .\`` – Craig Estey Aug 30 '16 at 23:18

1 Answers1

4

Your code is illegal (in both ISO C and GNU C): the body of a function declared as inline must appear in the same translation unit as any call to that function. But in your code it does not appear in app.c, which is why you get the undefined reference error.

Further, as mentioned in comments, in ISO C an inline function that is not also static, may not mention an array with internal linkage. (I don't know what GNU C's rules are in this area).

In comments you talk about stuff like "overhead of CALL" etc. But this has little or nothing to do with the inline keyword. The optimizer will produce the fastest possible code if you use an optimization switch. The purpose of the inline keyword is to allow function bodies to appear in header files.

One option would be to unmark the function as inline, and use the -O2 -flto switches with gcc.

Another option is to use the inline function but put the function body in the header file. In this case you will also need to use extern int data_array[]; etc, because it is not possible to define the array in the header file. Before doing this option then read this page. Here is some code that's compatible with both ISO C and GNU C:

// header file
extern int data_array[];

static inline int get_value(int index)
{
    return data_array[index];
}

// source file
#include "header.h"

int data_array[32];
Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • @AnT this is a C answer (as evinced by me saying "C" several times in the answer and not "C++"). See C11 6.7.4/7 "For a function with external linkage, the following restrictions apply: If a function is declared with an `inline` function specifier, then it shall also be defined in the same translation unit." (6.2.3/5 covers that `inline int get_value(int);` declares a function with external linkage). I changed the wording of that paragraph in my answer now; it's legal for the function body to be after the call but within the same unit. – M.M Aug 31 '16 at 01:01
  • Yes, you are right. I was thinking about a different matter. – AnT stands with Russia Aug 31 '16 at 01:54
  • @AnT OK, we can remove comments if you like – M.M Aug 31 '16 at 01:59
  • @M.M In GCC docs I found a statement that inline functions are used to eliminate function-call overhead. Direct quote: "This makes execution faster by eliminating the function-call overhead" Reference: https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc/Inline.html#Inline When a function call is made, it generates 4 assembly instructions: CALL, PUSH, POP and RET – Nulik Sep 02 '16 at 03:18
  • @Nulik try looking at the generated assembly(with optimization enabled) – M.M Sep 02 '16 at 04:15