1

Assuming that every source c file using a variable initialized in a C header file is declared using extern, that variable should be only allocated once no matter how many times a function defined in a source c file including that header and declaring that variable with extern is called.

So I'm referring to one way to ensure that constants used between functions defined in separate files are not allocated for every call to any function that uses that constant.

Now when i call a function in a header file under these conditions using the Haskell FFI, I would like to know if calling functions declared in that header file allocates that variable repeatedly or if it's allocated once. And if its not allocated only once, are there any simple ways to make sure it is?

Here's an example of the .hs, .h, and .c files.

Main.hs:

{-# LANGUAGE ForeignFunctionInterface #-}

module Main (main) where

foreign import ccall unsafe "cstuff.h cfnc"
  cfnc :: IO ()

main :: IO ()
main = do cfnc
          cfnc 
          cfnc

cstuff.h:

extern int myvar; 
void cfnc();

cstuff.c:

#include "cstuff.h"
#include <stdio.h>

int myvar = 1;
void cfnc() {
   printf("%i\n",myvar);
} 

So in this case cfnc was called was called 3 times and I would like to know if myvar is only allocated once or 3 times. And if its not only once what can i do to make sure it's only allocated once?

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
Anon
  • 375
  • 1
  • 7
  • 2
    `int myvar; myvar = 1; ` should be `int myvar = 1; ` and in the .c file. `extern int myvar;` should be in the .h file. – chi Jul 09 '23 at 15:28
  • You could print the address of the variable using `%p` in `printf("%p", &myvar)` (with `&`) to see if it changes. I didn't try it but I assume the allocation happens only one time, do you have reasons to believe this is not the case? – Marijn Jul 09 '23 at 15:35
  • @chi I now changed it to `int myvar = 1;`. But i don't think its correct to switch the extern like you suggest. From my understanding `extern` means `myvar` is defined elsewhere. If i define it in the c file then `myvar` would be allocated when `cfnc` is called. – Anon Jul 09 '23 at 15:40
  • @Marjin Thanks I'll try that. If it does change then I'll know for sure this can happen. But if it doesn't I still won't know if the compiler optimized it away in this specific case. I'm not sure how to prevent the compiler from optimizing it away to check that for sure. Do you know? – Anon Jul 09 '23 at 15:45
  • 3
    If you define it as a global variable, it should be allocated once on program startup. C allows multiple declarations of variables (with `extern`), but only one definition (e.g. `int x =1;`) in the whole program. To comply with this, typically one uses `extern` in the header, so that it can be #included many times, but makes a single .c file define the variable. – chi Jul 09 '23 at 15:48
  • @chi Okay I see. As long as i declare it as a global variable in the c file, what you said should be correct? – Anon Jul 09 '23 at 15:57
  • Yes, you have to _define_ it (not just declare it) in a single C file. Definitions of variables are those without `extern`. Declarations also include those with `extern`. (For functions, it's different -sigh-, but it does not matter here) – chi Jul 09 '23 at 16:00
  • @chi sorry yes i meant define it as a global variable – Anon Jul 09 '23 at 16:02

1 Answers1

6

Depending on exactly what you mean by allocated, it may in fact be allocated zero times! Check it out:

% objdump -t Main | grep myvar
00000000004a8418 g     O .data  0000000000000004              myvar

That 00000000004a8418 is the address that's been set aside, once and for all before the program even starts, to hold myvar. (The 0000000000000004 is how many bytes have been set aside -- just right for an int on my machine.) Here's evidence (though not proof) that's what it means. Changing cfnc to be

void cfnc() {
   printf("%i\n%p\n",myvar,&myvar);
}

the new output I get from running your program is:

1
0x4a8418
1
0x4a8418
1
0x4a8418

As you say, this is only evidence, not proof -- e.g. perhaps the compiler has done something clever. But no; not only did I run the compiler without optimizations turned on, this is also just the bog-standard thing that every C compiler I know of does for top-level variables.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380