Очень часто программистам приходится портировать код из одного языка программирования в другой, ведь не писать же свой “велосипед”, когда можно просто “скопипастить” чужой код и немного подправить… Однако, не все так просто! Существуют различные сложности, связанные с архитектурой языков, компиляторов и “железа”. Это, своего рода, “подводные камни”, для преодоления которых, при портировании кода из 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); // массив неявно преобразуемый в указатель