为什么我的C析构函数没有被调用?

huangapple go评论64阅读模式
英文:

Why is my C destructor not getting called?

问题

我有两个项目部分:一个包含主函数的example.c和一个包含所有API的api.c。它们分别编译,由API生成的二进制文件被示例用于成功进行API调用。

我已经设置了两个库,包含构造函数和析构函数:

example.c

__attribute__((constructor)) static void example_constructor() {
  printf("constructor: example\n");
  api_setup();
}

__attribute__((destructor)) static void example_destructor() {
  printf("destructor: example\n");
  api_teardown();
}

int main() {
  // 进行API调用
}
api.c

__attribute__((constructor)) static void api_constructor() {
  printf("constructor: api\n");
}

__attribute__((destructor)) static void api_destructor() {
  printf("destructor: api\n");
}

api_setup() {
  // 为API调用分配一个缓冲区
}

api_teardown() {
  // 读取+对缓冲区执行任务。发送到输出文件
  // 释放缓冲区
}

// 其他用于操作缓冲区的API定义

当像上面这样设置时,构造函数和析构函数都会在示例和API的主函数开始/结束时调用。事情运行得很顺利,但我希望api.c的构造函数/析构函数负责所有的设置和拆卸工作。如果我进行以下更改:

api.c

__attribute__((constructor)) static void api_constructor() {
  printf("constructor: api\n");
  api_setup(); // 在api.c构造函数中执行设置,而不是在example.c构造函数中执行
}

__attribute__((destructor)) static void api_destructor() {
  printf("destructor: api\n");
  api_teardown(); // 在api.c析构函数中执行拆卸,而不是在example.c析构函数中执行
}

// 其他用于操作缓冲区的API定义(包括设置/拆卸)

将设置移至api.c构造函数后,我发现构造函数会为example.capi.c都调用,但析构函数只会为example.c调用。

这是为什么呢?我该如何通过api.c的构造函数/析构函数执行所有的设置/拆卸工作?


这是你要翻译的部分。

英文:

I have two parts of my project: an example.c (which contains our main function) and an api.c (which contains all APIs). They are compiled separately, and the binaries generated by the API are used by the example to successfully make API calls.

I have set up both libraries to contain a constructor and destructor:

example.c

__attribute__((constructor)) static void example_constructor() {
  printf("constructor: example\n");
  api_setup();
}

__attribute__((destructor)) static void example_destructor() {
  printf("destructor: example\n");
  api_teardown();
}

int main() {
  // make API calls
}
api.c

__attribute__((constructor)) static void api_constructor() {
  printf("constructor: api\n");
}

__attribute__((destructor)) static void api_destructor() {
  printf("destructor: api\n");
}

api_setup() {
  // malloc a buffer to be used in the API calls
}

api_teardown() {
  // read + perform task on buffer. send to output file
  // free buffer
}

// other API definitions to manipulate the buffer

When set up like the above, constructors and destructors get called for both the example and API (at the start/end of example's main). Things work great but I'd like to have the api.c constructor/destructor responsible for all setup and teardown work. If I make changes:

api.c

__attribute__((constructor)) static void api_constructor() {
  printf("constructor: api\n");
  api_setup(); // doing setup in api.c constructor instead of example.c constructor
}

__attribute__((destructor)) static void api_destructor() {
  printf("destructor: api\n");
  api_teardown(); // doing teardown in api.c destructor instead of example.c destructor
}

// other API definitions to manipulate the buffer (including setup/teardown)

With the setup moved to the api.c constructor, I find that constructors get called for both example.c and api.c, but the destructor only gets called for example.c.

Why is this? And how could I go about performing all setup/teardown via the api.c constructor/destructor?

答案1

得分: 3

  • 使用这个属性在gcc中,你可以控制构造函数/析构函数的优先级。
  • 对于constructor,较小的数字表示较高的优先级。
  • 对于destructor,较小的数字表示较低的优先级。
void __attribute__((constructor(101))) c1(void) { printf("%s\n", __func__);}
void __attribute__((constructor(102))) c2(void) { printf("%s\n", __func__);}
void __attribute__((constructor(103))) c3(void) { printf("%s\n", __func__);}
void __attribute__((constructor(104))) c4(void) { printf("%s\n", __func__);}

void __attribute__((destructor(101))) d1(void) { printf("%s\n", __func__);}
void __attribute__((destructor(102))) d2(void) { printf("%s\n", __func__);}
void __attribute__((destructor(103))) d3(void) { printf("%s\n", __func__);}
void __attribute__((destructor(104))) d4(void) { printf("%s\n", __func__);}

void main(void)
{
}

链接:https://godbolt.org/z/9aGnnW487

英文:

Using this attribute in gcc you can control the priority of the constructors/destructors.

  • for constructor smaller number means a higher priority
  • for destructor smaller number means a lower priority
void __attribute__((constructor(101))) c1(void) { printf("%s\n", __func__);}
void __attribute__((constructor(102))) c2(void) { printf("%s\n", __func__);}
void __attribute__((constructor(103))) c3(void) { printf("%s\n", __func__);}
void __attribute__((constructor(104))) c4(void) { printf("%s\n", __func__);}

void __attribute__((destructor(101))) d1(void) { printf("%s\n", __func__);}
void __attribute__((destructor(102))) d2(void) { printf("%s\n", __func__);}
void __attribute__((destructor(103))) d3(void) { printf("%s\n", __func__);}
void __attribute__((destructor(104))) d4(void) { printf("%s\n", __func__);}

void main(void)
{
}

https://godbolt.org/z/9aGnnW487

huangapple
  • 本文由 发表于 2023年5月25日 02:19:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76326400.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定