2011-02-07 2 views
3

Я долго программист на C++, изучающий Аду для удовольствия. Если какая-либо из нижеперечисленных проблем является плохой, не стесняйтесь указывать ее. Я пытаюсь изучить способ Ады, но старые привычки трудно сломать (и я пропускаю Boost!)Ada Slicing with Strings

Я пытаюсь загрузить файл, который содержит целое число, пробел, а затем строка символов. Там может быть лучший способ сделать это, но я подумал, что я должен загрузить строку в строковый буфер, который, как я знаю, будет не более 80 символов. Я объявляю переменный буфер вроде следующих в соответствующем месте:

Line_Buffer : String(1..80); 

После открытия файла, я Перебери каждую строку и разделить буфер на символе пробела:

while not Ada.Text_IO.End_Of_File(File_Handle) loop 
    Ada.Text_IO.Get_Line(File_Handle, Item=>Line_Buffer, Last=>Last); 
    -- Break line at space to get match id and entry 
    for String_Index in Line_Buffer'Range loop 
    if Line_Buffer(String_Index) = ' ' then 
     Add_Entry(Root_Link=>Root_Node, 
     ID_String=> Line_Buffer(1..String_Index-1), 
     Entry_String=> Line_Buffer(String_Index+1..Last-1) 
     ); 
    end if; 
    end loop; 
end loop; 

Что происходит в Add_Entry это не так важно, но его спецификация выглядит следующим образом:

procedure Add_Entry(
    Root_Link : in out Link; 
    ID_String : in String; 
    Entry_String : in String); 

Я хотел использовать неограниченные строки, а не ограниченные строки, потому что я не хочу беспокоиться о необходимости указать размер здесь и там. Это компилируется и работает отлично, но внутри Add_Entry, когда я пытаюсь выполнить цикл над каждым символом в Entry_String, вместо того, чтобы индексы начинались с 1, они начинаются со смещения в исходной строке. Например, если Line_Buffer был «14 кремния», если цикл следующим образом, индекс идет от 4 до 10.

for Index in Entry_String'Range loop 
    Ada.Text_IO.Put("Index: " & Integer'Image(Index)); 
    Ada.Text_IO.New_Line; 
end loop; 

Есть ли лучший способ сделать это синтаксический так, что строки Перехожу к Add_Entry есть границы, начинающиеся с 1? Кроме того, когда я передаю отрезанную строку как параметр «in» для процедуры, является ли копией, созданной в стеке, или является ссылкой на используемую исходную строку?

ответ

6

Прежде всего, мои симпатии. Ада-строки, вероятно, самые разные вещи между C++ и Ada. Хуже всего то, что различия лежат на поверхности, поэтому наивные кодеры C/C++ начинают свою карьеру в Ada, думая, что их, возможно, нет, и они могут обрабатывать строки Ada, как они делают строки C. Теперь для вашего конкретного вопроса:

Массивы Ada (включая строки) имеют неявные границы, проходящие с ними. Это означает, что обычно нет необходимости в специальном контрольном значении (например, nul), и редко нужна отдельная переменная длины. Это также означает, что нет ничего особенного в отношении 1 или 0 или любого другого индекса.

Итак, правильный способ борьбы с массивами в Аде состоит в том, что вы не допускаете внутри подпрограммы, каковы ваши начальные и конечные границы. Вы их понимаете. Язык предоставляет 'first, 'last и 'range специально для этой цели. Из вашего примера, если вы хотите, чтобы напечатать смещение от начала данной строки (для какой-то странной причине), было бы:

for Index in Entry_String'Range loop 
    Ada.Text_IO.Put("Index offset: " & Integer'Image(Index-Entry_string'first)); 
    Ada.Text_IO.New_Line; 
end loop; 

OK. Теперь для разницы двух между Ada и C. Ваш параметр in равен не скопирован. Это очень важно, поэтому я немного закричу: Параметры Ada не передаются, как параметры C! Точные правила немного сложны, но для вашей цели принцип заключается в том, что Ада сделает разумную вещь. Если параметр может поместиться в регистр, он будет передан копией (или, возможно, регистром). Если параметр слишком большой для этого, он будет передан по ссылке. Вы не можете это решить. Это проблема оптимизации и будет выполняться компилятором.Но вы можете рассчитывать на то, что ваш компилятор не создает копии больших массивов, чтобы передать их в подпрограмму, которая в любом случае не позволяет изменять их. Это было бы глупо. Только полный идиот (или компилятор C++) мог бы сделать такую ​​вещь. Если вы когда-либо находите компилятор Ada, он сообщает об этом как об ошибке. Это было бы.

Наконец, в большинстве случаев творческое использование правил определения Ada позволит вам использовать идеально фиксированные постоянные «фиксированные» строки. Вам почти не нужно использовать динамические строки или отдельные переменные длины. К сожалению, Ada.Text_IO.Get_Line является одним из исключений. Если вы не слишком заботитесь о производительности (чего не следует, если вы читаете эту строку от пользователя), вы можете использовать Carlisle's routine to read in a perfectly-sized fixed string из Text_IO.

+0

Эти атрибуты довольно гладкие. Приятно не беспокоиться о значениях индекса. Еще одна особенность Ada, которую я изучаю (помимо типов и чистой читаемости до сих пор) –

+0

, как подразумевается TED, вы можете определить подтипы, а затем использовать диапазоны этих типов для создания и индексирования массивов, даже диапазонов, которые нестандартный (-5 .. 5), который устраняет необходимость смещения любой индексации до 0 или 1 :) – NWS

3

Если у вас все в порядке с установленными пакетами реализации GNAT, пакет Ada.Strings.Unbounded.Text_IO доступен.

Кроме того, дочерние пакеты Ada.Strings (специфичные для фиксированных, ограниченных или неограниченных строк) предоставляют некоторые полезные подпрограммы для обработки строк, такие как Index() для поиска определенных строк в других строках - полезны для определения встроенных пробелов: -)

Существует еще один пакет GNAT, GNAT.Array_Split (который поставляется с префиксами как GNAT.String_Split), который предоставляет больше подпрограмм, ориентированных на размыкание массивов (и строк).

+0

Спасибо. Я буду больше смотреть в пакеты. GNAT - единственный компилятор Ada, с которым я работаю, поэтому я также проверю GNAT. –

+0

Существует также небольшой рекурсивный трюк для чтения, который я видел для Get_Line, который предоставит вам строку в фиксированную фиксированную строку. http://www.adapower.com/index.php?Command=Class&ClassID=Basics&CID=202 –

+0

О, и дополнительные реквизиты для управления им до Ada.Strings.Fixed и друзей. Если он еще не понадобится, он скоро. –