【问题标题】:What is the "right" way to work with struct pointers and a C interface?使用结构指针和 C 接口的“正确”方法是什么?
【发布时间】:2021-02-26 14:39:26
【问题描述】:

我正在尝试设置一个系统,在该系统中我传递一个指向结构的指针,同时向最终用户隐藏结构的定义。我有两个似乎可行的选择,但我不知道我是否让这变得比需要的更难,错过权衡,或者只是做一些非常愚蠢的事情。对于任何方法,我都坚持使用 C,不能使用 C++。此外,这最终将需要与 Fortran 程序进行对话,我正在努力使其尽可能简单。

我有一个小工具来演示这个概念。选项一使用指向指针的 void 指针,以便我可以在必要时从函数返回一个状态整数。但是,我不喜欢在通话之前进行 malloc,因为我担心 Fortran 方面的事情。这可能是没有根据的,因为我还没有做过那个演示。选项二只是从函数返回一个 void 指针,但我失去了以这种方式返回状态的能力。对于这两个版本,我确实有一个自定义的免费功能,即使不一定使用确切的当前实现。该结构有它自己的 void 指针,它将根据选项输入进行定义,并且作为拆卸过程的一部分,它需要释放它。

#include <stdio.h>
#include <stdlib.h>

struct State
{
    int type;
    void *data;
};

int Init1(int option, void **state);
void* Init2(int option);

void printState(void *state);

void free1(void **state);
void free2(void *state);

void* allocateData(int option);

int main(int argc, char *argv[])
{
    void **ps1;
    void *s2;
    int ret;
    
    ps1 = malloc(sizeof(void*));
    ret = Init1(1, ps1);
    printState(*ps1);
    free1(ps1);

    s2 = Init2(2);
    printState(s2);
    free2(s2);

    return 0;
}

int Init1(int option, void **state)
{
    (*state) = malloc(sizeof(struct State));
    struct State* ret = *state;
    ret->type = option;
    
    return 0;
}

void free1(void **state)
{
    free(*state);
    free(state);
}

void* Init2(int option)
{
    struct State* ret = malloc(sizeof(struct State));
    ret->type = option;

    return ret;
}

void free2(void *state)
{
    free(state);
}

void printState(void *state)
{
    struct State* data = state;

    printf("Type : %d\n", data->type);
}

【问题讨论】:

  • 不需要void *。用户可以在不知道结构成员的情况下声明struct State *s
  • 同意@WilliamPursell - 检查“不透明结构”。
  • 另外,不需要初始 malloc。你可以做void *ps1; Init1(1, &amp;ps1);
  • 如果你使用 void 指针,你会失去很多 C 提供的类型安全性。不要设计带有 void 指针的接口。使用不透明类型或指向不透明类型的指针。示例见标准 I/O 库和 FILE 指针类型
  • 通过对不透明指针的快速阅读,看起来它在与 Fortran 接口时会增加一定程度的复杂性,尽管仍然可能。感谢您提供有关初始 malloc 的提示。

标签: c pointers


【解决方案1】:

stdio.h 中的FILE 类型为例。您可以公开类型名称而不公开其定义:

/**
 * State.h
 */
#ifndef STATE_H
#define STATE_H

/**
 * Create a typedef name for the *incomplete* type "struct State"
 */
typedef struct State STATE;

/**
 * Define your interface
 */
void   Init1( int, STATE ** );
STATE *Init2( int );

void   printState( STATE * );

void   sFree( STATE * );
void   sFree2( STATE ** );

#endif

然后你在实现文件中完成类型的定义:

/**
 * State.c
 */
#include "State.h"
#include <stdlib.h>
...

/**
 * Complete the type definition
 */
struct State {
  int type;
  void *data;
};

/**
 * Implement the interface
 */
int Init1( int option, STATE **s )
{
  *s = malloc ( sizeof **s ); // type definition is complete at this
  if ( *s )                   // point so we can use sizeof
  {
    (*s)->type = option;
  }
  return *s != NULL; // I'm *assuming* you want to return true (1)
}                    // if the allocation is successful

...

现在,当谈到与 Fortran 的互操作时……我帮不上什么忙。我在 30 多年前的 VAX 上做过一次,它不涉及像这样的不透明类型。

【讨论】:

  • 在使用不透明结构的同时,我能够在界面中使用 type(c_ptr) 来实现 Fortran 界面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多