- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我想定义一组东西,比如事件处理程序。的内容这个数组在编译时是完全已知的,但是定义在多个编译单元,分布在多个库中是相当解耦的,至少在最终(静态)链接之前是这样。我想要也保持这种方式 - 所以添加或删除编译单元将还可以自动管理事件处理程序而无需修改事件处理程序的中央列表。
这是我想做的事情的一个例子(但行不通)。
中央.h:
typedef void (*callback_t)(void);
callback_t callbacks[];
中央.c:
#include "central.h"
void do_callbacks(void) {
int i;
for (i = 0; i < sizeof(callbacks) / sizeof(*callbacks); ++i)
callbacks[i]();
}
foo.c:
#include "central.h"
void callback_foo(void) { }
callback_t callbacks[] = {
&callback_foo
};
酒吧.c:
#include "central.h"
void callback_bar(void) { }
callback_t callbacks[] = {
&callback_bar
};
我想要的是获得一个callbacks
数组,其中包含两个元素:&callback_foo
和 &callback_bar
。使用上面的代码,有显然有两个问题:
callbacks
数组被定义了多次。sizeof(callbacks)
在编译 central.c
时未知。在我看来,第一点可以通过合并链接器来解决两个 callbacks
符号而不是抛出错误(可能通过一些变量上的属性),但我不确定是否有类似的东西。即使有,sizeof 问题也应该以某种方式解决。
我意识到这个问题的一个常见解决方案是启动“注册”回调的函数或构造函数。然而,我只能看到两种实现方式:
由于我在内存有限的微 Controller 平台 (Arduino) 上运行,这些方法都对我没有吸引力。鉴于该数组在编译时已知,我希望有一种方法让编译器也看到这个。
我找到了 this和 this解决方案,但那些需要自定义链接器脚本,这在我的编译环境中是不可行的运行(特别是因为这需要明确命名每个链接描述文件中的这些特殊数组,所以只需要一个链接描述文件添加在这里不起作用)。
This solution是迄今为止我发现的最好的。它使用链表在运行时填充,但使用每个静态分配的内存单独编译单元(例如,下一个指针分配给每个函数指针)。尽管如此,这些下一个指针的开销不应该需要 - 有没有更好的方法?
也许结合链接时间优化的动态解决方案可以以某种方式导致静态分配?
也欢迎就替代方法提出建议,尽管需要元素具有静态的事物列表和内存效率。
此外:
最佳答案
正如在之前的一些回答中评论的那样,最好的选择是使用自定义链接描述文件(带有 KEEP(*(SORT(.whatever.*)))
输入部分)。
无论如何,它可以在不修改链接器脚本的情况下完成(下面的工作示例代码),至少在某些带有 gcc 的平台上(在 xtensa 嵌入式设备和 cygwin 上测试)
假设:
怎么做:
这是非常具体的,因为正确的方法是使用自定义链接描述文件,但如果我们在标准链接描述文件中找到始终“保留”和“排序”的部分,则不这样做也是可行的。
通常,对于 .ctors.*
输入部分是这样的(标准要求 C++ 构造函数按函数名的顺序执行,在标准的 ld 脚本中是这样实现的),所以我们可以破解并尝试一下。
请注意它可能不适用于所有平台(我已经在 xtensa 嵌入式架构和 CygWIN 中对其进行了测试,但这是一种黑客技巧,所以...)。
此外,由于我们将指针放在构造函数部分,我们需要使用一个字节的 RAM(对于整个程序)来跳过 C 运行时初始化期间的回调代码。
测试.c:
一个库,注册了一个名为test
的模块,并在某个时候调用它的回调
#include "callback.h"
CALLBACK_LIST(test);
void do_something_and_call_the_callbacks(void) {
// ... doing something here ...
CALLBACKS(test);
// ... doing something else ...
}
callme1.c:
客户端代码为模块 test
注册两个回调。生成的函数没有名字(它们确实有名字,但它是神奇地生成的,在编译单元内是唯一的)
#include <stdio.h>
#include "callback.h"
CALLBACK(test) {
printf("%s: %s\n", __FILE__, __FUNCTION__);
}
CALLBACK(test) {
printf("%s: %s\n", __FILE__, __FUNCTION__);
}
void callme1(void) {} // stub to be called in the test sample to include the compilation unit. Not needed in real code...
callme2.c:
客户端代码正在为模块 test
注册另一个回调...
#include <stdio.h>
#include "callback.h"
CALLBACK(test) {
printf("%s: %s\n", __FILE__, __FUNCTION__);
}
void callme2(void) {} // stub to be called in the test sample to include the compilation unit. Not needed in real code...
回调.h:
还有魔法……
#ifndef __CALLBACK_H__
#define __CALLBACK_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef void (* callback)(void);
int __attribute__((weak)) _callback_ctor_stub = 0;
#ifdef __cplusplus
}
#endif
#define _PASTE(a, b) a ## b
#define PASTE(a, b) _PASTE(a, b)
#define CALLBACK(module) \
static inline void PASTE(_ ## module ## _callback_, __LINE__)(void); \
static void PASTE(_ ## module ## _callback_ctor_, __LINE__)(void); \
static __attribute__((section(".ctors.callback." #module "$2"))) __attribute__((used)) const callback PASTE(__ ## module ## _callback_, __LINE__) = PASTE(_ ## module ## _callback_ctor_, __LINE__); \
static void PASTE(_ ## module ## _callback_ctor_, __LINE__)(void) { \
if(_callback_ctor_stub) PASTE(_ ## module ## _callback_, __LINE__)(); \
} \
inline void PASTE(_ ## module ## _callback_, __LINE__)(void)
#define CALLBACK_LIST(module) \
static __attribute__((section(".ctors.callback." #module "$1"))) const callback _ ## module ## _callbacks_start[0] = {}; \
static __attribute__((section(".ctors.callback." #module "$3"))) const callback _ ## module ## _callbacks_end[0] = {}
#define CALLBACKS(module) do { \
const callback *cb; \
_callback_ctor_stub = 1; \
for(cb = _ ## module ## _callbacks_start ; cb < _ ## module ## _callbacks_end ; cb++) (*cb)(); \
} while(0)
#endif
main.c:
如果你想试一试......这是一个独立程序的入口点(经过测试并在 gcc-cygwin 上工作)
void do_something_and_call_the_callbacks(void);
int main() {
do_something_and_call_the_callbacks();
}
输出:
这是我的嵌入式设备中的(相关)输出。函数名称在 callback.h
中生成,并且可以重复,因为函数是静态的
app/callme1.c: _test_callback_8
app/callme1.c: _test_callback_4
app/callme2.c: _test_callback_4
在 CygWIN 中...
$ gcc -c -o callme1.o callme1.c
$ gcc -c -o callme2.o callme2.c
$ gcc -c -o test.o test.c
$ gcc -c -o main.o main.c
$ gcc -o testme test.o callme1.o callme2.o main.o
$ ./testme
callme1.c: _test_callback_4
callme1.c: _test_callback_8
callme2.c: _test_callback_4
链接器映射:
这是链接器生成的映射文件的相关部分
*(SORT(.ctors.*))
.ctors.callback.test$1 0x4024f040 0x0 .build/testme.a(test.o)
.ctors.callback.test$2 0x4024f040 0x8 .build/testme.a(callme1.o)
.ctors.callback.test$2 0x4024f048 0x4 .build/testme.a(callme2.o)
.ctors.callback.test$3 0x4024f04c 0x0 .build/testme.a(test.o)
关于c++ - 在链接时合并全局数组/从多个编译单元填充全局数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24283277/
我试图要求 test/unit 的新版本(即不是与 ruby 捆绑的版本) .根据 instructions我用 gem i test-unit 安装它.但是现在当我需要 test/unit我似乎
简短版本是: 我有一个 systemd 单元,我想在调用时检查脚本的返回代码: systemctl status service.service 长版本:我有一个 lsb init 脚本正是这样做的,
我正在使用反射动态创建一个类的实例,这工作正常,除非尝试通过单元测试执行此操作 - 我使用的是 MS 测试框架。 我收到熟悉的错误:“无法加载文件或程序集‘Assy’或其依赖项之一。系统找不到指定的文
我想知道测试网站“界面功能”的最佳实践是什么。 我对哪些方法可用于测试界面和动态生成的内容感兴趣。特别是,我很难弄清楚是否可以为需要用户交互的操作创建自动化测试,或者这是否只是浪费时间,我应该让一些
我有一个简单的 Python 服务,其中有一个无限执行某些操作的循环。在各种信号上,sys.exit(0) 被调用,这导致 SystemExit 被引发,然后如果可以的话应该进行一些清理。 在测试中,
我正在使用 OpenCV 2.4.2 这是 OpenCV 文档中的引文 C++: void HoughLinesP(InputArray image, OutputArray lines, doubl
忙于 C# 中的自动化测试用例,我们需要在每次测试后恢复数据库快照。问题是,当运行多个测试时它会失败,因为“其他用户正在使用数据库时无法更改数据库状态。” 我们使用 SqlConnection.Cle
我阅读了 C# 规范并用谷歌搜索了它,但一无所获。 我 99% 肯定 C# 中没有像单元命名空间指令这样的功能,但问题是:为什么?是否有惯用或技术原因? 这很方便,尤其是当我们的大部分文件都由单个命名
我目前正在尝试向我的应用程序(一个非常老的项目......评论说 iOS 2.0)添加单元测试(精确的应用程序测试)并且总是偶然发现 undefined symbols for architectur
我正在使用Delphi 7,并且有一个新单元要在我的项目中使用。我已经编译了新的。当我尝试通过将其添加到uses子句在项目中使用此单元时,出现错误,提示未找到.dcu文件。我还尝试将文件的完整路径放在
场景:我需要编写一个复杂的nHibernate查询,该查询将返回预计的DTO,但是我想使用TDD方法。该方法如下所示: public PrintDTO GetUsersForPrinting(int
您可以通过运行以下命令在事件 html 设置中显示 Jupyter 笔记本: $ jupyter nbconvert untitled.ipynb --to slides --post serve 有
如何在一个网站上拥有多个 AdSense 单元? Google 提供的唯一代码是按单位计算的。 (adsbygoogle = window.adsbygoogle || []).push({})
我刚刚开始为大量代码编写测试。有很多类依赖于文件系统,即读取 CSV 文件、读/写配置文件等。 当前测试文件存储在项目(这是一个 Maven2 项目)的 test 目录中,但由于多种原因该目录并不总是
我对 TDD 还很陌生,在单元测试方面也不是很老练,所以才有这个问题。我有这个用 PHP 编写的遗留函数 function foo(){ x = bar(); y = baz();
我创建了一个程序,在 Swing 窗口的一侧显示结果过滤选项,但默认情况下它们水平相邻显示,这浪费了我在 BorderLayout 的西侧分配的空间。我可以在构造函数或添加语句中传递任何内容来将它们堆
标题不好的借口:如果有人能更好地描述它,请做。 我有一个 WeakList类,它“基本上”是一个 List> (虽然不是字面意义上的派生自列表,但它应该对用户完全透明)。 现在的基本思想是“如果引用的
我正在尝试在 UITableView 上添加两个原型(prototype)单元。但是,我不知道如何验证是否能够为每个原型(prototype)“返回”正确的单元格。你们能帮我一下吗? func ta
我正在使用 CloudKit 作为数据库创建一个简单的待办事项列表应用程序。目前我可以添加和删除对象,但对编辑对象感到困惑。 编辑项目 Controller protocol EditItemCont
我正在针对以下任务训练 RNN:给定一个包含 30 个单词的序列,然后将该序列分类为二进制类。 在我的网络中拥有超过 30 个单元(LSTM、GRU 或普通 RNN)有好处吗?我在网上看到过很多例子,
我是一名优秀的程序员,十分优秀!