Заметки о языке

Использование D-строк в библиотеках, написанных на Си
Строки в D — это просто массив символов. В языке C, все строки заканчиваются двоичным нулем. При взаимодействии с библиотеками, написанными на C, это необходимо учитывать. Как Phobos, так и Tango имеют методы для конвертации C-строк в D, и наоборот.

Разберем такой пример. Есть Си-шная функция: printf. Попробуем подсунуть ей массив с символами:
import tango.stdc.stdio;

void main()
{
   char[] string = "Hello";
   printf("%s", &string);
}
На выходе, в консоли, получаем символ — ♣. Забавно. Функция printf, если вначале указать формат «%s», будет ожидать от последующих аргументов указатель на массив символов.

Поскольку по размеру тип char в C и D идентичен, я указываю &string, наивно полагая, что в результате получу указатель на первый элемент массива. Однако такая конструкция (&string) дает некорректные результаты потому, что в памяти массив представлен таким образом: сначала идет информация о длине массива, а потом данные.

Чтобы исправить ситуацию, нужно функции передавать именно данные, а не весь массив. Способов масса: можно сослаться (корректным для языка D способом) на первый элемент массива; можно воспользоваться встроенным свойством всех массивов в языке D.ptr; или воспользоваться методом, который предлагает сам создатель языка: явно указать длину массива там, где возможно. Продемонстрирую кодом:
import tango.stdc.stdio;

void main()
{
   char[] string = "Hello";
   printf("%s", &string[0]); // способ первый. Явно указываем
                             // первый элемент массива  
   printf("\n");
 
   printf("%s", string.ptr); // второй способ. Используем встроенное свойство,
                             // которое также указывает на первый 
                             // элемент массива
   printf("\n");
 
   printf("%.*s", string.length, string.ptr); // третий способ. Явно указываем 
                                              // на длину передаваемой строки
   printf("\n");
}
Однако возникает вопрос: почему printf корректно выводит D-строки, ведь они не содержат двоичный ноль на конце? Ответ я нашел в скромной заметке про взаимодействие с языком Си: «[...] string literals, when they are not part of an initializer to a larger data structure, have a '\0' character helpfully stored after the end of them».

Указывается, что строковые литералы все-таки автоматически обзаводятся двоичным нулем. Получается, что никаких лишних телодвижений, кроме как правильной адресации, не требуется.

2 комментария:

  1. Я тоже пытаюсь освоить системный язык программирования. Сделал выбор за D. Так как C++ для моего мозга слишком сложен. Единственно, что меня смущает,
    это сложность компиляции существующих оберток для GTK, SQLite и т.п.
    Опять же непонятно как развивается сообщества языка, когда появится нормальная платформа для разработки GUI-программ. Чисто хакерский пока язык без нужных библиотек(основное приемущество java).

    ОтветитьУдалить
    Ответы
    1. А какие проблемы с компиляцией GtkD? По мне, отличный биндинг, лучшего и не надо. Для GUI самое то.

      Удалить