原地址
作者:(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
声明.@无垃集
的.