首页 > 解决方案 > 使用结构指针和 C 接口的“正确”方法是什么?

问题描述

我正在尝试设置一个系统,在其中传递指向结构的指针,同时向最终用户隐藏结构的定义。我有两个似乎可行的选择,但我不知道我是否让这件事变得比需要的更难,错过了权衡,或者只是做一些非常愚蠢的事情。对于任何方法,我都坚持使用 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);
}

标签: cpointers

解决方案


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

/**
 * 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 上做过一次,它不涉及像这样的不透明类型。


推荐阅读