C到D:struct作为类型并初始化?

时间:2017-04-11 19:48:15

标签: d ctod

我有这些C宏,并希望将它们转换为纯D(与原始C文件接口)。

#define __KS_TYPE(type_t) \
    typedef struct __kstream_t { \
        unsigned char *buf; \
        int begin, end, is_eof; \
        type_t f; \
    } kstream_t;


#define __KS_BASIC(type_t, __bufsize) \
    static inline kstream_t *ks_init(type_t f) \
    { \
        kstream_t *ks = (kstream_t*)calloc(1, sizeof(kstream_t)); \
        ks->f = f; \
        ks->buf = (unsigned char*)malloc(__bufsize); \
        return ks; \
    } \
    static inline void ks_destroy(kstream_t *ks) \
    { \
        if (ks) { \
            free(ks->buf); \
            free(ks); \
        } \
    }

这是我目前的实施:

import std.stdio;
import core.stdc.config;
import core.stdc.stdlib;

struct __kstream_t(type_t) {
    ubyte *buf;
    int begin, end, is_eof;
    type_t f;
  }

mixin template __KS_BASIC(type_t, ubyte __bufsize){
  // mixin(__KS_TYPE!type_t);
  alias kstream_t = __kstream_t!type_t;
  static kstream_t *ks_init(type_t f)
  {
    kstream_t *ks = cast(kstream_t*)calloc(1, kstream_t.sizeof);
    ks.f = f;
    ks.buf = cast(ubyte*)malloc(__bufsize);
    return ks;
  }
  static void ks_destroy(kstream_t *ks)
  {
    if (ks) {
      free(ks.buf);
      free(ks);
      writeln("Destroyed struct.");
    }
  }

}

void main(){
  mixin __KS_BASIC!(int, 12);

  auto ks = ks_init( 14);
  ks.buf[0] = 125;
  writeln("ks.f: ", ks.f, ", buf: ", ks.buf[0]);
  ks_destroy(ks);


}

D版本当前运行正常,但是我可以对代码进行任何调整和修剪吗?它看起来仍然很C-ism。例如,kh_init可以是这样的:

static kstream_t *ks_init(type_t f){
    kstream_t* ks;
    ks.f = f;
    return ks;
  }

但是这个版本提供了sementation fault

此外,在D版本的ks_initks_destroy中手动处理内存有什么好处吗?

2 个答案:

答案 0 :(得分:0)

它是段错误的,因为您没有在堆栈上分配kstream_t,而是分配一个初始化为null的指针。 要在堆栈上分配它,你会做:

kstream_t ks;  // still bad

但是当您尝试访问其任何字段时,这仍然会在main()中发生段错误,因为一旦范围退出就会释放堆栈分配,在这种情况下ks_init()

你应该在gc上分配它:

auto ks = new kstream_t;

编辑:抱歉,我没有谈论缓冲区的分配,你可以将maclloc内存提供给GC,这样他就可以为你管理它了

ks.buf = cast(ubyte*)malloc(__bufsize);
import core.memory : GC;
GC.addRange(ks.buf, __bufsize);

然而,似乎你有兴趣将该代码移植到惯用的D.然后有一些事情要考虑,你已经找到了大部分:

  1. 使用数组而不是指针。
  2. 使用new而不是malloc。
  3. 将穷人的模板(宏)转换为D模板。
  4. 在struct中移动方法。
  5. 最好将命名方式更改为D Style
  6. 代码可能如下所示:

    import std.stdio;
    
    struct Kstream(T) {
        ubyte[] buf;
        int begin, end, is_eof;
        T f;
    
        this(T f, ubyte bs)
        {
            this.f = f;
            this.buf = new ubyte[bs];
        }
    
        ~this()
        {
          writeln("Destroyed struct.");
        }
    }
    
    void main(){
    
        auto ks = Kstream!int(14, 12);
        ks.buf[0] = 125;
        writeln("ks.f: ", ks.f, ", buf: ", ks.buf[0]);
    }
    

    EDIT2:如果您不想避免GC,可以将缓冲区设为静态数组:

    import std.stdio;
    
    struct Kstream(T, size_t N) {
        ubyte[N] buf;
        int begin, end, is_eof;
        T f;
    
        this(T f)
        {
            this.f = f;
        }
    
        ~this()
        {
            // we cannot call writeln in @nogc code
            //writeln("Destroyed struct.");
        }
    }
    
    @nogc
    void main(){
        auto ks = Kstream!(int, 12)(14);
        ks.buf[0] = 125;
    
        // we cannot call writeln in @nogc code
        //writeln("ks.f: ", ks.f, ", buf: ", ks.buf[0]);
    }
    

    沃尔特·布莱特有一个很棒的主题演讲叫做Memory DisAllocation - slides,在那里他建议避免使用GC分配,并展示了一些技巧,我建议这样做。
    但是我们不能总是避免GC /堆分配,如果数组很大,我们必须使用new D中垃圾收集器的当前实现很慢(并且我们正在逐渐消除它,很快就不再有GC),但是当时它不会那么慢,大部分时间你都不会真的需要额外的速度,所以你不需要使用new

答案 1 :(得分:0)

这是一个更D版本,@ DejanLekic的评论和@Sahmi回答有一些启发。我发布了一个答案,因为我不想改变原来的问题。

import std.stdio;
import core.stdc.config;
import core.stdc.stdlib;

struct __kstream_t(type_t) {
    ubyte *buf;
    int begin, end, is_eof;
    type_t f;

  this(type_t f, ubyte bs){
    this.f = f;
    this.buf = cast(ubyte* )malloc(bs);//Can this be avoided or more D?
  }

  }

mixin template __KS_BASIC(type_t, ubyte __bufsize){
  alias kstream_t = __kstream_t!type_t;
    static kstream_t* ks_init(type_t f){
    auto ks = new kstream_t(f, __bufsize);
    return ks;
  }

    static void ks_destroy(kstream_t *ks)
  {
    if (ks) {
      destroy(ks);
      writeln("Destroyed struct.");
    }
  }

}


void main(){

  mixin __KS_BASIC!(int, 12);

  auto ks = ks_init( 14);
  ks.buf[0] = 125;
  writeln("ks.f: ", ks.f, ", buf: ", ks.buf[0]);
  ks_destroy(ks);


}