C 到 D:结构为类型并初始化?
C to D: struct as type and initialize?
我有这些 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_init
和 ks_destroy
中手动处理内存有什么好处吗?
它会出现段错误,因为您没有在堆栈上分配 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。然后需要考虑一些事项,您已经了解其中的大部分内容:
- 使用数组代替指针。
- 使用 new 而不是 malloc。
- 将穷人的模板(宏)转换为 D 模板。
- 在结构中移动方法。
- 最好将命名风格更改为D Style。
代码可能如下所示:
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]);
}
Walter Bright 有一个很棒的主题演讲 Memory DisAllocation - slides,他在其中建议避免 GC 分配并展示了一些这样做的技巧,我推荐它。
然而,我们不能总是避免 GC/heap 分配,如果数组很大,我们必须使用 new.
D 中垃圾收集器的当前实现速度很慢(我们正在摆脱它,很快就不再有 GC),但大多数时候它并没有那么慢,大多数时候你并不需要额外的速度,因此您无需使用 new
.
这是一个更 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);
}
我有这些 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_init
和 ks_destroy
中手动处理内存有什么好处吗?
它会出现段错误,因为您没有在堆栈上分配 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。然后需要考虑一些事项,您已经了解其中的大部分内容:
- 使用数组代替指针。
- 使用 new 而不是 malloc。
- 将穷人的模板(宏)转换为 D 模板。
- 在结构中移动方法。
- 最好将命名风格更改为D Style。
代码可能如下所示:
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]);
}
Walter Bright 有一个很棒的主题演讲 Memory DisAllocation - slides,他在其中建议避免 GC 分配并展示了一些这样做的技巧,我推荐它。
然而,我们不能总是避免 GC/heap 分配,如果数组很大,我们必须使用 new.
D 中垃圾收集器的当前实现速度很慢(我们正在摆脱它,很快就不再有 GC),但大多数时候它并没有那么慢,大多数时候你并不需要额外的速度,因此您无需使用 new
.
这是一个更 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);
}