【问题标题】:Portable way to "unpoint" a pointer typedef?“取消指向”指针typedef的便携式方法?
【发布时间】:2010-11-09 15:52:42
【问题描述】:

不幸的是,这是在某些外部库中定义的:无法触摸!

// library.h
typedef struct {
    long foo;
    char *bar;
   /* ... (long & complex stuff omitted) */
} *pointer_to_complex_struct_t;

现在问题:如何声明一个complex_struct_t变量?

  • 理想的解决方案,但不允许! (无法更改外部库):

    // library.h
      /* ... (long & complex stuff omitted) */
    } complex_struct_t, *pointer_to_complex_struct_t;
    
    
    // my.h
    extern complex_struct_t my_variable;
    
  • 非便携式解决方案(gcc):

    // my.h
    extern typeof( * (type_placeholder)0 )  my_variable; // Thanks caf!
    
  • 其他?更好的?谢谢!

奖励问题:函数指针的相同问题(以防有任何区别;我对此表示怀疑)。


附加奖励:下面是完全相同的问题,但使用的是函数而不是结构。这对简短的回答(“否”)没有任何影响,这是我最初感兴趣的唯一答案。我没想到有些人会死去试图了解并通过创造性的解决方法完成我的工作,这就是为什么我将问题从函数简化为结构(函数指针具有特殊的隐式转换规则以方便 混淆)。但是,嘿,为什么不呢?让我们开始复制粘贴变通方法竞赛。有些解决方法可能比其他解决方法更好。

///// library.h //////
// Signature has been simplified
typedef double (*ptr_to_callback_t)(long, int, char *);
// Too bad this is not provided: typedef double callback_t(long, int, char *);

///// my.h /////
// This avoids copy-paste but is not portable
typedef typeof( * (ptr_to_callback_t)0 ) callback_t;

extern callback_t callback_1;
extern callback_t callback_2;
extern callback_t callback_3;
// etc.

简短回答 = 否,目前没有可替代 typeof 的便携式替代品

基本的复制粘贴解决方法适用于 functions,但不适用于 structs。编译器将匹配重复的函数类型,但不会关联重复的结构类型:需要强制转换,重复的结构类型会在没有编译警告的情况下发散。

【问题讨论】:

  • 他们会这样做正是因为他们当然不希望你声明这样的变量。例如,可能无法初始化结构,该结构保证适用于库的过去和/或未来版本,但他们已经为您提供了成员,以便您可以阅读它们或类似的东西。所以,既然你弄乱了库的约束,为什么不弄乱库头(不是库本身,只是你在代码中包含的头)?
  • 对不起,我误导了你:我的真实例子实际上是函数,而不是结构。我将它简化为一个结构,因为我想不惜一切代价避免整个“函数 == 函数指针”混乱。顺便说一句,这种混乱可能是让“图书馆”作者陷入这种不幸的 typedef 的原因——请不要高估这个(实际上是内部的)“图书馆”:-)
  • @mu 和其他人:这个问题是关于 C 语言从理论、标准的角度来看的(缺乏)能力。这不是为了完成工作。直到现在我才意识到将不同的复制粘贴解决方法相互比较可能会有一些价值。
  • 您可以将 GCC 方言版本改进为单行:typeof(*(pointer_to_complex_t)0) my_variable;

标签: c typedef typeof


【解决方案1】:

不,很遗憾,标准 C 无法做到这一点。但使用 C++,一个简单的元函数就可以解决问题。

但是你可以复制粘贴结构的定义,从而保持原始不变

typedef struct {
 ///same  struct
} complex_struct_t;

这个解决方案的缺点是表达式&complex_struct_t 不是pointer_to_complex_struct_t 类型,而是指向未命名struct {//your members} 的类型指针; 如果您需要该功能,您将需要 reinterpret_casting...

【讨论】:

  • 一般来说,我讨厌复制粘贴,原因很明显。但也许在我的 (function typedef) 情况下,任何分歧都会在编译时早期检测到;我会尽力确保这一点。谢谢。
  • @MarcH:这个“解决方案”的可悲之处在于 &complex_struct_t 不会是 pointer_to_complex_struct_t 类型
  • &@secure:有趣。我意识到我低估了函数和结构之间的区别。
  • @MarcH:结构和函数完全不同——前者包含读取和写入的数据,后者被调用和执行。也许如果你写你想要实现的东西会有所帮助,因为由于固有的差异,complex_struct_t my_variable; 很难转化为函数。你自己试过了吗?编译器说了什么?
【解决方案2】:

如前所述,您的问题的答案是“否”;如果你只有一个类型定义

typedef struct {...} *ptr_to_struct;

那么就没有(标准的、可移植的)方法来提取结构类型。如果你必须创建一个结构的实例,你能做的最好的就是

ptr_to_struct s = malloc(sizeof *s);

然后使用-> 组件选择运算符(或通过取消引用s 并使用. 运算符,但您不想这样做)来引用结构中的字段。

你问过同样的事情是否适用于函数指针;你真的需要准确地说明你的意思。如果你有类似的情况

typedef struct {...} *ptr_to_struct;
ptr_to_struct foo() {...}

那么情况和上面一模一样;您没有办法声明该类型的变量。

【讨论】:

  • 我刚刚添加了上述问题的函数指针变体。它与您在答案的后半部分中假设的不同且更简单:我建议您删除后半部分。
  • @MarcH:按建议编辑。
【解决方案3】:

制作头文件的本地副本并包含它而不是原始文件。现在你可以做任何你想做的事。如果这个库可以更改(更新或其他任何内容),您可以编写一个小脚本来自动执行这些步骤,并在您编译时从您的 makefile 中调用它。只要确保不要盲目粘贴到标题中,搜索特定行(} *pointer_to_complex_struct_t;),如果不再找到则抛出错误。

如果此标头使用此库的其他标头,您可能必须对包含的搜索路径小心一点。另外,如果自己被其他标题包含,则按包含顺序。

编辑(对于您在评论中提到的真正目标):您不能使用函数指针来执行此操作。只要用typedef的签名写你想要的函数,就可以兼容指针,可以被它调用。

【讨论】:

  • 是的,我也可以简单地忽略 typedef 并在任何地方复制类型,包括在我的头文件中。对于这个问题,我可以看到多个基于复制粘贴的解决方法,但老实说,如果我发现复制粘贴令人满意,我就不会来这里了。
【解决方案4】:

怎么样:

pointer_to_complex_struct_t newStruct ( void ) {
    pointer_to_complex_struct_t ptr = 
         (pointer_to_complex_struct_t) malloc ( sizeof (*pointer_to_complex_struct_t) );
    return ptr;
}

您必须通过 ptr-> 引用新创建的结构,但您可以创建新结构。

当然,这可能有效,也可能无效,具体取决于结构的实际使用方式。想到的例子是:如果结构以

结尾怎么办
char data[0];

数据用于指向结构后面的内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多