d移植c代码数组
原地址
作者:(m.p)
移植c接口时,免不了与数组打交道,可能为串.尽管d与c的数组实现不一样,但基本构造块是一样的.因而,只要记得区别,就容易兼容.
在d中用c接口时,要转换c代码至d.直接用c,从中受益.移植时尽量保持原样.然后继续看声明/初化及如何转换.还要讲多维数组,d数组分析,从c函数中传递数组,及如何利用垃集.现在用c的都少了.
声明1维数组:
int c0[3];
栈上连续分配,c0有可能初化.全局变量/静态本地变量初化为0.如definit.c:
#include <stdio.h>
// global (can also be declared static)
int c1[3];
void main(int argc, char** argv)
{
static int c2[3]; // static local
int c3[3]; // non-static local
printf("one: %i %i %i\n", c1[0], c1[1], c1[2]);
printf("two: %i %i %i\n", c2[0], c2[1], c2[2]);
printf("three: %i %i %i\n", c3[0], c3[1], c3[2]);
}
打印:
one: 0 0 0
two: 0 0 0
three: -1 8 0
等价的d如下:
int[3] d0;
曾经可以用c风格数组,不过现在已弃用了,现在会报编译错误.
Error: instead of C-style syntax, use D-style int[3] d0
主要是为了风格一致性.d主要是从右到左读,与c风格不一样.考虑如下指针声明:
int* p0, p1;
d中都是指针,而c则是p0为指针,p1为整.d中都是类型在左,符号在右.考虑:
int d1[3], d2[3];
int[3] d4, d5;
使c代码非法,提高代码的一致性.提高了可读性.
d0,c0的另一个区别是d0始终会默认初化为预定义的类型.初值.数组初化为元素的初值.
转换c到d时,默认初化可能是个陷阱.考虑:
// static variables are default initialized to 0 in C
static float vertex[3];
some_func_that_expects_inited_vert(vertex);
直接翻译为d会出错,因为float.init == float.nan,而不是0.转换c时,一定要小心,哪个c变量未显式初化.哪个期望初化,及d中基本类型的默认初值.否则,真是掉坑里了.可用=空来禁止d的默认初化.
这对读值前加载值的数组及初值无用(仅是未初化标记)时,很有用.
float[16] matrix = void;
setIdentity(matrix);
默认初化,只是为了区别未初化值.常见错误是浮的初值为float.nan,而符的初值为0xFF(无效变长码).这样的值都是未初化的标志,初值一般没用.是整/极打破规则,因为任意值都是有意义的.不能说这是未初化.因而将0/假作为默认值,浮/符则要尽快显式初化.
显式初化数组
c方式:
int ci0[3] = {0, 1, 2}; // [0, 1, 2]
int ci1[3] = {1}; // [1, 0, 0]
int ci2[] = {0, 1, 2}; // [0, 1, 2]
int ci3[3] = {[2] = 2, [0] = 1}; // [1, 0, 2]
int ci4[] = {[2] = 2, [0] = 1}; // [1, 0, 2]
可见:
元素用初化列表中元素初化.不够则补0.省略长度,则用初化列表的长度.用[索引]=值来指定相应位值.没有索引的,初化为0.省略长度时,用最大索引作为长度基.其余为0.假定初化器比数组短.而gcc在如果更长的话则初化前面的,忽略后面的.并警告.可以混合指定与非指定.
// [0, 1, 0, 5, 0, 0, 0, 8, 44]
int ci5[] = {0, 1, [3] = 5, [7] = 8, 44};
注意,有的c编译器不支持c99.转换为d,小心:
int[3] wrong = {0, 1, 2};
int[3] right = [0, 1, 2];
d不是用{}初化,而是用[].产生错误:
Error: a struct is not a valid initializer for a int[3]
d中用{}来初化构.注意别与构字面量混淆了.
下个惊奇:
// int ci1[3] = {1};
int[3] di1 = [1];
产生编译错误:
Error: mismatched array lengths, 3 and 1
长度不匹配.看ci2.
// int ci2[] = {0, 1, 2};
int[] di2 = [0, 1, 2];
在c中,[数]与[]是没啥区别的.而d中作了区分.如果直接复制到d,就会出问题.d区分为静态/动态数组.而c始终是固定数组.后者在d中为动态数组/切片.静态数组的初化器必须与数组长度相等.d不允许小于数组长度的初化器.动态数组可伸缩大小.也可以不初化.而c中int foo[]这样是不行的.只有当初化器出现时,才可省略长度.可见c数组主要就是静态数组.
// gcc says "缺少数组大小'illegalC'"
// int illegalC[]
int[] legalD;
legalD ~= 10;
legalD为空数组,用~=附加.动态数组在显式初化时分配内存.如无初化器,一般在添加第1个元素时分配,默认用垃集.尽管编译器可决定在栈上分配是安全的,来优化.至于分配策略,看需要.参见d数组文章
用@无垃集时,区分静态动态数组就比较重要了.
@nogc void main()
{
int[] di2 = [0, 1, 2];
}
此时,动态数组不管用了.
Error: array literal in @nogc function D main may cause a GC allocation
静态数组,则在栈上分配.而c程序员,则糊涂了.其实就是c中数组为静态数组,而d中必须显式指定大小.见垃集不是敌人
总之.c有指定数组初化器(c99),d也支持,只是语法不一样.
// [0, 1, 0, 5, 0, 0, 0, 8, 44]
// int ci5[] = {0, 1, [3] = 5, [7] = 8, 44};
int[] di5 = [0, 1, 3:5, 7:8, 44]
int[9] di6 = [0, 1, 3:5, 7:8, 44];
看起来就像字典,但却是数组.对动态/静态数组都适用.
项 | 要点 |
|---|---|
1 | d有静态/动态数组,c只有静态数组. |
2 | 在栈上分配静态,垃集堆上分配动态数组. |
3 | 未初化静态数组初化为元素类型.初值. |
4 | 可显式初化动态数组,并按初化器长度作为长度. |
5 | 不能在@无垃集域中显式初化动态数组. |
6 | 未初化动态数组是空的. |
还可以用std.array最近添加的staticArray函数来转换类似int ci2[] = {0, 1, 2};的c声明.@无垃集的.
浙公网安备 33010602011771号