【问题标题】:C generic type as function argument inputC 泛型类型作为函数参数输入
【发布时间】:2025-12-21 18:10:12
【问题描述】:

所以我有两个不同的结构,其中我将访问的所有属性都是相同的。而且我还有一个函数,谁的论点,我希望能够接受两者中的任何一个。示例:

typedef struct{
    int whatnot = 14;
    int thing[11];
} TH_CONFIG;

typedef struct{
    int whatnot = 3;
    int thing[5];
} TH_CONFIG_2;

*_CONFIG var;

void fun(*_CONFIG input)
{
    input.whatnot = 5;
}

int main(){
    fun(var);
}

我可能有一种暗示,我应该使用 void 作为我可以进行类型转换的类型或其他东西?但我的搜索只得到了关于函数指针、模板和 C# 的东西。

编辑:*_CONFIG 在语法上并不正确,它表示我不知道在那里做什么,但它应该是 _CONFIG 类型

【问题讨论】:

  • void fun(*_CONFIG input) - 这是一个语法错误。
  • 您可能想了解unions
  • 这两种结构不兼容; int whatnot = 3; 表示法无效 C; *_CONFIG var; 无效 C; void fun(*_CONFIG input) 是无效的 C。一般来说,一个函数应该只适用于一种类型;否则,它缺乏功能凝聚力。如果必须,您可以通过void * 和其他标识void * 指向的类型的值传递值。或者您可以使用 union 的类型。如果联合中的所有类型都存在该成员并且它包含单独的值,您甚至可以使用 .whatnot 成员来识别您正在处理的类型。

标签: c function types struct arguments


【解决方案1】:

可能的解决方案。

  1. 只需对它们都使用长度为 11 的数组。您真的用完了操作系统上的最后 6 个字节吗?
  2. 将其设为动态数组。
  3. 只用汇编写,你显然不关心 C 的更高层次。
  4. 使用支持模板或多态的 C++ 等语言。
  5. 只需传入您关心的struct 的参数即可。

    void fun(int* whatnot) { *whatnot = 5; }

    int main() { 有趣(&myStruct.whatnot); 返回0; }

  6. 考虑到准 OO 设计。

    结构{ 诠释什么; } typedef 通用;

    结构 TH_CONFIG_1 { 普通普通; 诠释事物[11]; };

    结构 TH_CONFIG_2 { 普通普通; 诠释事物[5]; }

但如果你坚持...

void fun(void* input) {
    ( (int)(*input) ) = 5;
}

或者...

void fun(void* input) {
    ( (TH_CONFIG*) input)->whatnot = 5; // may have been a TH_CONFIG_2, but who cares?
}

注意:这不会通过任何 C 商店的代码审查。

【讨论】:

  • 1.是 2. 不能 3. 不 4. 不能 5. 争论太多,但感谢第一个非居高临下的建议 6. 我认为不会真正解决问题吗?我仍然会有 2 个不同的结构没有被输入到单个函数中。我可能是错的。前进:谢谢您的最后建议,此代码未经过审核。
  • @DanielCardin 公平地说 3 是唯一居高临下的建议。我很惊讶你的内存如此紧张,对于那些认为自己受内存或 CPU 限制但实际上只是过早优化的人来说,有 99 比 1 的 SO 问题,所以我必须勤奋对此。如果您更彻底地回答“您尝试过什么?”,您将在 SO 上获得更好的支持。即解释为什么 1、2 和 4 不在讨论范围内。 6 您将与 5 结合使用以减少“参数过多”的问题。但是,如果您真的要使用 7,那么您只是将自己从 C 中破解出来并编写无法维护的代码。
  • @DanielCardin 基本上,如果我处于您的位置并且假设 1、2 和 4 是不可接受的,我会称 5 为正确的权衡。太多的参数比绕过打字更可取。
  • 一旦我看到傲慢,它就会渗入其他一切。我不必选择 7,但与具有荒谬数量的论点相比,它似乎是最简单/最好的解决方案。我可以看到 6 将如何聚合所有非数组 args,但这将如何解决不同的 TH_CONFIG_1 和 _2?
  • @DanielCardin 6 并不能单独解决不同的类型。它解决了 5 的非托管参数问题。我绝对更喜欢非托管 args 到 7 中的解决方案......如果其他人决定按字母顺序重新排序你的参数,实现 6 等,它将在运行时中断。不了解该方法的危险,您不应该使用它。
【解决方案2】:

您可以使用任何指针类型并对其进行强制转换。

如果您访问的所有属性都相同,我猜一个是另一个的扩展(因为属性需要从结构的开头具有相同的偏移量)。在这种情况下,您可能需要使用此模式:

struct base {
  int foo;
  char **strings;
};

struct extended {
  struct base super;
  double other_stuff;
};

由于super 位于struct extended 的开头,因此您可以毫无问题地将struct extended * 转换为struct base *。当然,您可以通过在 struct extended 的开头重复相同的字段来做到这一点,但那样您就是在重复自己。

【讨论】:

  • 它们实际上是相同的结构,但具有不同的值和数组长度,我不能真正 malloc,需要硬编码。