【问题标题】:Link Multiple Declarations to Same Definition将多个声明链接到相同的定义
【发布时间】:2013-05-18 05:45:30
【问题描述】:

我已经用 C(不是 C++)实现了一个链表,用于存储指向数据的指针。我想对其函数有多个声明(以提供类型安全),但让它们中的每一个都链接到相同的定义(因为指向不同数据类型的指针之间没有实际区别,所以使用相同的代码可以减少空间)。

有没有人对如何实现这一点(或任何更好的方法)有任何想法?便携式解决方案显然是最好的,但我真的只需要在 GCC 中工作的东西。

【问题讨论】:

  • 编写多个声明真的能给你带来任何类型安全吗?我假设您有重载的插入/删除函数 - 是什么阻止您使用一种类型插入并使用另一种类型删除?
  • @derekerdmann:其中一个声明将采用 int*(例如),因此如果您尝试将该声明传递给 myStruct*,编译器会报错。该定义将采用无效*。编译器会将每个声明视为一个单独的函数,并且只有在链接器获取到它们时它们才会变得相同。
  • 声明还需要采用void* 才能接受myStruct* - 这是编译器在确定参数是否匹配时所查看的内容,而不是定义。
  • @derekerdmann:对不起;我不够清楚。会有多个 add_int(int*)、add_myStruct(myStruct*) 等形式的声明。这样,编译器就不允许像你说的那样给 add_int 一个 myStruct。这就是类型安全的来源。然后,在链接阶段,所有声明都链接到通用 add(void*) 以消除冗余。
  • 除了它并没有真正给你类型安全。链表在void* 上运行,因此没有什么可以阻止您调用add_int 来插入一个值,并调用get_myStruct 来删除完全相同的值。它实际上并没有让您的操作更安全,而是由您来跟踪哪些类型存储在哪些列表中。

标签: c


【解决方案1】:

我相信您可以使用函数原型的 typedef 和 将通用解决方案(处理void*s)转换为特定原型。这对于编译应该是安全的,因为所有指针的大小都相同。

考虑这个例子:

do_something.h:

typedef void (*do_something_with_int_t)(int *i);
extern do_something_with_int_t do_something_with_int;

typedef void (*do_something_with_string_t)(char *s);
extern do_something_with_string_t do_something_with_string;

do_something.c

#include "do_something.h"

void do_something_generic(void* p) {
    // Do something generic with p
}


do_something_with_int_t do_something_with_int =
    (do_something_with_int_t)do_something_generic;

do_something_with_string_t do_something_with_string =
    (do_something_with_string_t)do_something_generic;

只要 do_something_generic 真正与数据类型无关(即 真的p 指向的内容无关),就可以了。

【讨论】:

    【解决方案2】:

    如果它是 C(不是 C++),那么下面的代码就可以了。您可以根据自己的需要调整概念。

    tt.h

    typedef struct {
        int ii;
    } Type_1;
    
    typedef struct {
        int ii;
    } Type_2;
    
    int foo_1(Type_1* ptr) __attribute__((alias("foo")));
    int foo_2(Type_2* ptr) __attribute__((alias("foo")));
    

    tt.c

    #include <stdio.h>
    
    #include "tt.h"
    
    int main() {
        Type_1 t_1;
        Type_2 t_2;
        foo_1(&t_1);
        foo_2(&t_2);
    }   
    
    int foo(void* arg) {
        printf("foo: %p\n", arg);
    }
    

    【讨论】:

    • @anthony-arnold:我并不真正关心可移植性,所以我将在我的代码中使用 Ziffusion 的答案(为了提高效率;我相信你的答案每次调用需要一两条额外的指令)。但是,我接受您的回答,因为对于以后可能遇到此问题的人来说,这是更一般的答案。谢谢你们俩!
    • @LonelyIsland 请参阅this question 以了解有关效率的说明。一个好的编译器会生成几乎相同的机器代码。
    • @anthony-arnold:我认为 GCC 会优化它,但我在考虑未优化的情况......我不知道为什么。无论如何,好点子,我想我毕竟会使用你的方式。
    • @LonelyIsland 未优化的情况可能因您的编译器而异。 MSVC 将函数指针调用包装在一个对堆栈进行完整性检查的函数中。但那是为了调试构建,您必须接受牺牲才能正确开发代码。对于发布,您将打开优化。
    【解决方案3】:
    #include <stdio.h>
    struct common_type {
        int type;
    };
    
    struct type1 {
        int type;
        int value;
    };
    
    struct type2 {
        int type;
        char* p;
    };
    
    int func(void *para) {
        switch (((struct common_type*)para)->type) {
            case 1:
                printf("type1,value:%d\n",((struct type1*)para)->value);
                break;
            case 2:
                printf("type2,content:%s\n",((struct type2*)para)->p);
                break;
        }
    }
    
    int main() {
        char *s = "word";
        struct type1 t1 = {1,1};
        struct type2 t2;
        t2.type = 2;
        t2.p = s;
        func((void*)&t1);   
        func((void*)&t2);
    }
    

    【讨论】:

    • 你读过这个问题吗?您的回答解决了多重定义的常见问题,这不是我的问题。我的问题实际上是相反的,对多个声明使用一个定义。感谢您为提供帮助所付出的努力,但如果您为正确的问题付出努力,我将更加感激。
    • 在这种情况下,将定义放在头文件中,并将声明放在使用结构的文件中。我已经写了一些附加代码,你是这个意思吗?
    • 否;这仍然解决了错误的问题。我正在寻找一种将多个声明都链接到同一个“通用”函数的方法。
    • @LonelyIsland 好的,我更新了一段新代码,旧代码已被删除。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-18
    • 1970-01-01
    相关资源
    最近更新 更多