Очень часто программистам приходится портировать код из одного языка программирования в другой, ведь не писать же свой «велосипед», когда можно просто «скопипастить» чужой код и немного подправить… Однако, не все так просто! Существуют различные сложности, связанные с архитектурой языков, компиляторов и «железа». Это, своего рода, «подводные камни», для преодоления которых, при портировании кода из C в D, может помочь наш очередной перевод статьи Idiomatic D.
Глобальные переменные должны быть помечены как __gshared
Переменные в глобальной области видимости находятся в локальном хранилище потоков (Thread Local Storage, TLS), если они не квалифицированы как shared
или __gshared
. Вы, вероятно, захотите использовать __gshared
по причине неясного будущего shared.
// Глобальная переменная в C int my_global_var; // Эквивалент в D __gshared int myGlobalVar;
long и unsigned long
long
и unsigned long
в C имеют переменный размер, ни один встроенный тип не эквивалентен D!
Рекомендуемый способ — использовать c_long
и c_ulong
из модуля core.stdc.config
.
// Объявление функции в C unsigned long countBeans(const long *n) // Эквивалент в D import core.stdc.config; c_ulong countBeans(const(c_long)* n);
c_int
и c_uint
также имеются для замены int
и unsigned int
, но поскольку в большинстве архитектур они 32-битные, вместо этого обычно они просто переводятся с помощью int
и uint
.
char
В C тип char
может относиться либо к signed char
, либо к unsigned char
, в зависимости от реализации.
В D char
всегда является целым числом без знака (от 0 до 255). Если вам нужен эквивалент signed char
, используйте byte
.
// Объявление функции в C unsigned char * computeBlurb(signed char *data); // Эквивалент в D char* computeBlurb(byte* data);
Объявление многомерных массивов
// Объявление массива в C int myMatrix[4][2] = { { 1, 2}, { 3, 4}, { 5, 6}, { 7, 8} }; // Эквивалент в D int[2][4] myMatrix = [ [ 1, 2], [ 3, 4], [ 5, 6], [ 7, 8] ];
Перечислимые типы без пространства имен
// Объявление enum в C typedef enum { STRATEGY_RANDOM, STRATEGY_IMMEDIATE, STRATEGY_SEARCH } strategy_t; // Эквивалент в D alias strategy_t = int; enum : strategy_t { STRATEGY_RANDOM, STRATEGY_IMMEDIATE, STRATEGY_SEARCH }
Это позволяет избежать необходимости писать Strategy_t.STRATEGY_IMMEDIATE
вместо STRATEGY_IMMEDIATE
при переносе кода C.
Анонимные struct и union
D предоставляет ограниченную форму анонимной вложенной структуры и объединения (union), но их нельзя использовать для перевода анонимной структуры C:
// Анонимная структура C struct Foo { struct { int x; } bar; }; // Эквивалент D struct Foo { private struct bar_t { int x; } bar_t bar; }
Явное преобразование массива в указатель
При переносе из C вам, вероятно, придется спамить .ptr
везде, где массив неявно преобразуется в указатель.
// В C void sum(const int *array, int n); int coeff[16]; sum(coeff, sizeof(coeff) / sizeof(int)); // В D void sum(const(int)* array, int n); int[16] coeff; sum(coeff.ptr, coeff.sizeof / int.sizeof); // массив неявно преобразуемый в указатель