当从 Haskell 调用该头文件中的函数时,在 C 头文件中初始化的变量是否只分配一次?

B.A*_*.A. 1 haskell haskell-ffi

假设使用在 C 头文件中初始化的变量的每个源 c 文件都使用 声明extern,则无论调用源 c 文件中定义的函数(包括该头文件并声明该变量)多少次,该变量都应该只分配一次extern

因此,我指的是一种方法,以确保不会为使用该常量的任何函数的每次调用分配单独文件中定义的函数之间使用的常量。

现在,当我在这些条件下使用 Haskell FFI 调用头文件中的函数时,我想知道调用该头文件中声明的函数是否会重复分配该变量,或者是否分配了一次。如果它不只分配一次,是否有任何简单的方法来确保它是?

以下是 .hs、.h 和 .c 文件的示例。

主要.hs:

{-# LANGUAGE ForeignFunctionInterface #-}

module Main (main) where

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

main :: IO ()
main = do cfnc
          cfnc 
          cfnc
Run Code Online (Sandbox Code Playgroud)

cstuff.h:

extern int myvar; 
void cfnc();
Run Code Online (Sandbox Code Playgroud)

cstuff.c:

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

int myvar = 1;
void cfnc() {
   printf("%i\n",myvar);
} 
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下 cfnc 被调用了 3 次,我想知道是否myvar只分配一次或 3 次。如果它不仅仅是一次,我该怎么做才能确保它只分配一次?

Dan*_*ner 6

根据分配的确切含义,它实际上可能被分配零次!一探究竟:

% objdump -t Main | grep myvar
00000000004a8418 g     O .data  0000000000000004              myvar
Run Code Online (Sandbox Code Playgroud)

00000000004a8418是在程序启动之前就已经预留出来的地址,用于保存myvar. (这0000000000000004是已预留的字节数 - 正好适合int我的机器上的字节数。)这是证据(尽管不是证明),这就是它的含义。改变cfnc

void cfnc() {
   printf("%i\n%p\n",myvar,&myvar);
}
Run Code Online (Sandbox Code Playgroud)

我运行你的程序得到的新输出是:

1
0x4a8418
1
0x4a8418
1
0x4a8418
Run Code Online (Sandbox Code Playgroud)

正如你所说,这只是证据,而不是证明——例如,也许编译器做了一些聪明的事情。但不是; 我不仅在没有打开优化的情况下运行编译器,而且这也是我所知道的每个 C 编译器对顶级变量所做的标准事情。