在为嵌入式系统编程时,通常不允许使用malloc().大部分时间我都能够处理这个问题,但有一件事让我感到恼火:它使我无法使用所谓的"不透明类型"来启用数据隐藏.通常我会做这样的事情:
// In file module.h
typedef struct handle_t handle_t;
handle_t *create_handle();
void operation_on_handle(handle_t *handle, int an_argument);
void another_operation_on_handle(handle_t *handle, char etcetera);
void close_handle(handle_t *handle);
// In file module.c
struct handle_t {
int foo;
void *something;
int another_implementation_detail;
};
handle_t *create_handle() {
handle_t *handle = malloc(sizeof(struct handle_t));
// other initialization
return handle;
}
Run Code Online (Sandbox Code Playgroud)
你去:create_handle()执行malloc()来创建'实例'.通常用于防止必须使用malloc()的构造是更改create_handle()的原型,如下所示:
void create_handle(handle_t *handle);
Run Code Online (Sandbox Code Playgroud)
然后调用者可以这样创建句柄:
// In file caller.c
void i_am_the_caller() {
handle_t a_handle; // Allocate a handle on the stack instead of malloc()
create_handle(&a_handle);
// ... a_handle …Run Code Online (Sandbox Code Playgroud) 我通常知道在C中设计通用链表数据结构的两种方法.我想知道哪个更好.在提出问题之前,我将简要介绍这两种方法:
一种方法是围绕如下结构构建函数:
struct list_element {
struct list_element *prev;
struct list_element *next;
void *data;
};
Run Code Online (Sandbox Code Playgroud)
显然,数据指针指向有效负载.list元素struct在有效负载之外.这就是glib如何设计其双链表设施:http://library.gnome.org/devel/glib/2.26/glib-Doubly-Linked-Lists.html
另一种方法是在Linux内核中完成它的方式:http://isis.poly.edu/kulesh/stuff/src/klist/.list元素结构中没有指向有效负载的void指针.相反,list元素struct包含在payload结构中:
struct list_element {
struct list_element *prev;
struct list_element *next;
};
struct person {
char name[20];
unsigned int age;
struct list_element list_entry;
};
Run Code Online (Sandbox Code Playgroud)
一个特殊的宏用于获取指向有效负载结构的指针,给定指向list_entry的指针,其名称包含有效负载结构和有效负载结构的类型(list_entry()宏).
最后,问题是:构建链表的两种方法的后者有什么优势?有几次我听说有人说第二种比第一种更"通用",但为什么呢?我甚至认为第一种方法更通用,因为有效负载结构与列表实现无关,而第二种方法则不然.
第二种方法的另一个缺点是如果要将有效负载放在多个列表中,则应该为有效负载结构中的每个列表设置struct list_element成员.
编辑:总结到目前为止,我看到了两个对我来说很重要的答案:
我已经addr2line为函数地址工作了:
$ nm -S executable | grep main
08048742 000000a0 T main
$ addr2line -e executable 08048742
/home/blablabla/src/main.c:80
Run Code Online (Sandbox Code Playgroud)
不幸的是,它仅在我提供函数的地址时才有效,当传递数据符号的地址(例如crc表的地址)时,它永远无法解析文件/行号:
$ nm -S executable | grep tableCRC
080491bc 00000200 r tableCRC
$ addr2line -e executable 080491bc
??:0
Run Code Online (Sandbox Code Playgroud)
我猜这种调试信息不包含在数据中,因为这个功能可能用于分析回溯,但是可能有一个编译器/链接器选项来强制这个?
我想使用输出addr2line来生成有关文件或模块使用的内存大小的详细信息(而不是'size'工具报告的全局编号).
总结:今天我发现当没有预编译头文件构建DLL时,当你尝试使用它时会出现一个奇怪的错误.
禁用预编译头时,构建DLL会很好.但是,只要附加DLL(编译时或运行时),就会导致错误"无效参数".两种情况下的实际错误代码都不同.当附加编译时弹出一个错误代码为0xc000000d的对话框,当调用LoadLibrary()它时返回一个NULL指针并GetLastError()返回0x57.
编辑:
我发现当禁用增量链接时问题就会消失.不知何故,我错过了Visual Studio在运行附加到DLL编译时的客户端时显示的以下错误:
'TestClient.exe': Loaded 'D:\Projects\PchDllTest2\Debug\TestClient.exe', Symbols loaded.
'TestClient.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll', Cannot find or open the PDB file
'TestClient.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', Cannot find or open the PDB file
'TestClient.exe': Loaded 'D:\Projects\PchDllTest2\Debug\TestDll.dll', Symbols loaded.
SXS: RtlCreateActivationContext() failed 0xc000000d
LDR: LdrpWalkImportDescriptor() failed to probe D:\Projects\PchDllTest2\Debug\TestDll.dll for its manifest, ntstatus 0xc000000d
Debugger:: An unhandled non-continuable exception was thrown during process load
The program '[5292] TestClient.exe: Native' has exited with code -1073741811 (0xc000000d).
Run Code Online (Sandbox Code Playgroud)
根据要求,函数声明:
#ifdef __cplusplus …Run Code Online (Sandbox Code Playgroud) 我正在开发一个支持错误处理的宏。
#define Try(e, call) ( (e == OK) && ((e = call) != OK) )
Run Code Online (Sandbox Code Playgroud)
它可以用作 if 语句的表达式:
if (Try(err, SomeFunction(foo, bar))) {
// Entered only if err was OK before the if-statement and SomeFunction()
// returned a non-OK value.
}
Run Code Online (Sandbox Code Playgroud)
如果err在 if 语句之前已经不正常,则不会调用该函数。在 if 语句之后err将设置为 的返回值SomeFunction()。
到现在为止还挺好。但是我也想使用没有 if 语句的宏:
Try(err, SomeFunction(foo, bar));
Run Code Online (Sandbox Code Playgroud)
在这种情况下,GCC 给出以下警告:
warning: value computed is not used [-Wunused-value]
Run Code Online (Sandbox Code Playgroud)
这就是我的问题所在:如何重写宏以使 GCC 不会产生此警告。我知道可以使用标志禁用警告(但我想为其他代码启用它)或通过将结果显式转换为void. 以下语句代码不会产生警告:
(void) Try(err, SomeFunction(foo, bar));
Run Code Online (Sandbox Code Playgroud)
但是Try() …
我迷路了..我想使用编译器资源管理器来试验多线程 C 代码,并从一段简单的代码开始。该代码是用-O3.
static int hang = 0;
void set_hang(int x) {
hang = x;
}
void wait() {
while (hang != 0) {
// wait...
}
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,这是编译器的输出:
set_hang(int):
mov dword ptr [rip + hang], edi
ret
wait():
ret
Run Code Online (Sandbox Code Playgroud)
我花了一段时间才注意到我正在将代码编译为 C++ 而不是 C。切换到 C 给了我一些我所期望的东西:
set_hang:
mov DWORD PTR hang[rip], edi
ret
wait:
mov eax, DWORD PTR hang[rip]
test eax, eax
je .L3
.L5:
jmp .L5
.L3:
ret
Run Code Online (Sandbox Code Playgroud)
因此,当编译为 C++ 时,wait()无论之前将哪个值传递给 ,总是返回set_hang() …
为什么这段代码不会导致y == 0x100?
uint8_t x = 0xff;
unsigned y = ++((unsigned)x);
Run Code Online (Sandbox Code Playgroud)
请在此处查看:http://codepad.org/dmsmrtsg