【发布时间】:2016-10-14 17:33:26
【问题描述】:
假设我写了一个这样的简单动态库:
lib.h
#pragma once
extern int x;
extern int p(void);
lib.c
#include <lib.h>
#include <stdio.h>
x = 0;
int p(void) {
printf("lib: %d\n", x++);
return 0;
}
交流
#include <lib.h>
#include <stdio.h>
int main(void) {
for (; !p(); x--) printf("a.c: %d\n", x);
return 0;
}
b.c
#include <lib.h>
#include <stdio.h>
int main(void) {
for (; !p(); x = 0) printf("b.c: %d\n", x);
return 0;
}
a 和 b 会打印什么? 我能想到几件可能发生的事情:
- 链接器错误:
x已声明extern但从未定义。 - 每个进程都有自己的
x,包括lib。 (b.c 始终为 0,a.c 倒计时,lib 倒计时) - 每个进程都有自己的
x与lib共享。 (a.c 和 b.c 始终为 1,lib 始终为 0) - 所有进程共享相同的
x,包括lib。 (a.c、b.c 和 lib 返回随机值) - 所有进程共享相同的
x,包括lib,直到lib以外的其他人写入它,然后该进程将获得它自己的x版本,不与lib(在某处在线阅读此内容)。 (lib 总是递增,b.c 总是打印 0,a.c 倒计时)
通常会发生什么?我们应该知道的编译器/平台之间是否存在任何不一致?我们可以强制一种行为(我在想__declspec(dllexport)、编译器标志等)吗?
【问题讨论】:
-
我认为链接器错误部分无关紧要,因为您必须做一些工作才能产生忽略未定义符号的可执行结果。对于运行时的情况,共享库在运行时单独链接到每个进程,可写页面是默认的写时复制。正常情况下 a 和 b 都有自己的 x 副本(大星号),没有单独的 lib 进程。在 Windows 上,如果显式请求,dll 可能包含进程之间共享的数据,但显式创建和使用共享内存段来共享内存更为常见和灵活。
-
@ArtYerkes AFAIK,如果链接器不知道
lib导出extern int x,则链接器将出错,这可能意味着,使用该链接器,库无法导出变量。至于你的其余评论,如果我理解正确的话:写信给例如extern int x对其他进程不可见,但 将 对lib可见,仅当使用该进程调用时(很像案例 3,除了所有进程最初共享相同的x)?是这样,还是您(使用“写入时复制”)的意思是当您写入变量时,它将创建一个lib不使用的新变量? -
@ArtYerkes 顺便说一句,把这个变成答案:)
标签: c shared-libraries extern