Zig конвертирует std.os.argv в argv типа C

У меня есть проект zig, интегрируемый с библиотекой C (xlib). В библиотеке есть метод, который требует, чтобы я передал ему весь массив argv в качестве параметра. В определении zig extern ожидаемый тип параметра argv библиотечной функции — [*c][*c]u8.

Поскольку я использую Linux, я использую некроссплатформенный способ получения аргументов cli в zig.

var argv = std.os.argv;

Зиг-аргументы имеют тип [][*:0]u8. У меня есть 2 вопроса.

  1. Каков наиболее прагматичный способ преобразования/сборки зиг-варг в C-варги ( [][*:0]u8 -> [*c][*c]u8)
  2. Что именно означает [*c][*c]u8?

Давно я не работал на таком низком уровне. Правильно ли я понимаю, что [*c][*c]u8 — это список указателей c, где каждый указатель c является указателем на первый символ строки, завершающейся нулем?

Я ничего не знаю о zig, но массив указателей на char, передаваемый функции xlib C, должен быть завершен нулевым указателем, чтобы отметить конец списка. В C int main(int argc, char **argv) массив, на который указывает argv, содержит argc+1 указатели argv[0] на argv[argc], и argv[argc] будет нулевым указателем. Предыдущие указатели будут указателями на строки, завершающиеся нулем. argv[0] (если оно не равно нулю, как и должно быть), традиционно интерпретируется как указание на имя программы.

Ian Abbott 17.04.2024 18:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
167
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Каков наиболее прагматичный способ приведения/сборки зиг-варгов в C-варги ( [][*:0]u8 -> [*c][*c]u8)

@ptrCast свойство .ptr на срезе:

const argv = std.os.argv;
const c_ptr: [*c][*c]u8 = @ptrCast(argv.ptr);

(Я не думаю, что здесь необходимо приведение указателя - он должен иметь возможность неявно приводить argv.ptr, но отказывается неявно приводить дочернего элемента указателя)

Что именно означает [*c][*c]u8? / Правильно ли я понимаю, что [*c][*c]u8 — это список указателей c, где каждый указатель c является указателем на первый символ строки, завершающейся нулем?

Указатели зигзага немного сбивают с толку. Существуют указатели, срезы и массивы значений с различными параметрами и схожим синтаксисом:

  • *u8 : указатель на значение u8. Можно разыменовать (value.*), но нельзя индексировать (value[0]).
  • [*]u8 : многоэлементный указатель неизвестной длины на значение u8. Можно индексировать, но нельзя разыменовывать.
  • [*c]u8: тип указателя элемента «один или несколько», который существует только для совместимости с C. Он может быть как разыменованным, так и индексированным.
    • в c все указатели могут быть как разыменованы, так и проиндексированы:
      int myvalue = 0;
      int* mypointer = &myvalue;
      *mypointer = 1; // allowed
      mypointer[0] = 2; // allowed
      
    • при преобразовании c в zig zig не знает, предназначен ли указатель c для одного элемента или массива.
    • вот почему он генерирует указатели [*c], которые допускают оба использования.
  • []u8 : срез, который представляет собой указатель и длину. это похоже на struct {ptr: [*]u8, len: usize}. Его можно индексировать, но нельзя разыменовывать.
  • [N]u8 : тип массива значений. Это не указатель, хотя и выглядит так.

Указатели и фрагменты неизвестной длины могут иметь контрольное значение. [:0]u8 указывает, что срез имеет 0 после последнего элемента (slice[slice.len] == 0). [*:0]u8 указывает, что, хотя длина неизвестна, элемент после последнего элемента массива должен быть 0.

Как обычные указатели, так и указатели неизвестной длины могут неявно приводиться к указателям совместимости c.

Теперь, к вопросу

  • [*c] один или несколько указателей элемента, содержащих
    • [*c] один или несколько указателей элемента, содержащих
      • ты8

Вы правы в своей интерпретации.


Поскольку мы знаем, что это массивы, лучшим представлением в zig было бы [*][*:0]u8, массив массивов. Однако translate-c не знает этого, поэтому выдает указатели совместимости c.

  • [*] указатель массива неизвестной длины, содержащий
    • [*:0] неизвестная длина 0-дозорный указатель массива, содержащий
      • ты8

Поскольку мы также знаем длину внешнего массива (с помощью argv), мы можем объединить указатель [*][*:0]u8 и длину usize в срез: [][*:0]u8.

Вот почему std.os.argv возвращается [][*:0]u8.

Ах, значит, моя первая попытка была правильной! Я сделал именно так, как вы предлагаете. К сожалению, я получаю ошибку из библиотеки (целочисленный параметр выходит за пределы рабочего диапазона). Я предполагаю, что это что-то специфическое для xlib, а не преобразование зигзагообразных переменных в переменные в стиле c.

Alex 18.04.2024 18:57

Вы можете принудить без @ptrCast, если сделаете дочерние указатели const: const c_ptr: [*c]const [*c]u8 = argv.ptr;. В случае OP заголовок библиотеки должен будет объявить параметр как char *const argv[] или char *const *argv.

djpohly 06.05.2024 17:05

Другие вопросы по теме