小编Bar*_*art的帖子

静态分配不透明数据类型

在为嵌入式系统编程时,通常不允许使用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 embedded opaque-pointers

39
推荐指数
4
解决办法
6479
查看次数

实现链表的两种方法:哪种更好?

我通常知道在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成员.

编辑:总结到目前为止,我看到了两个对我来说很重要的答案:

  • 使用第一种方法:从列表中删除有效负载涉及循环遍历完整列表,直到找到指向有效负载的列表元素.您不需要使用第二种方法执行此操作.(Patrick的答案)
  • 使用第一种方法,您必须为每个元素执行两个malloc():一个用于有效负载,另一个用于list元素struct.使用第二种方法,一个malloc()就足够了.(罗迪的回答)

c linked-list

9
推荐指数
2
解决办法
4192
查看次数

为什么只为函数使用addr2line

我已经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'工具报告的全局编号).

c debugging elf

6
推荐指数
1
解决办法
1268
查看次数

为什么在没有预编译头的情况下构建DLL会在使用时导致奇怪的错误?

总结:今天我发现当没有预编译头文件构建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)

c c++ dll precompiled-headers visual-studio

5
推荐指数
2
解决办法
3795
查看次数

防止宏的 GCC 警告“未使用计算的值”

我正在开发一个支持错误处理的宏。

#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 gcc gcc-warning

5
推荐指数
1
解决办法
2464
查看次数

为什么现代编译器针对 C++11 及更高版本对此进行了优化

我迷路了..我想使用编译器资源管理器来试验多线程 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() …

c++

3
推荐指数
1
解决办法
98
查看次数

++((unsigned)x)的意外结果,x是uint8_t?

为什么这段代码不会导致y == 0x100

uint8_t x = 0xff;
unsigned y = ++((unsigned)x);
Run Code Online (Sandbox Code Playgroud)

请在此处查看:http://codepad.org/dmsmrtsg

c gcc

1
推荐指数
1
解决办法
241
查看次数