Вперед вызов функции C printf со строкой

Я вызываю функцию C printf с S" ..." строка и я бью неверный адрес памяти. Как правильно передать указатель на строку с нулевым символом в конце, которая была создана на стороне Forth в C.

Вот две версии Hello World в gforthодин использует выделенный синтаксис для записи литеральной строки, а другой - type со строкой, сохраненной как значение (хотя и тривиально)

Вот helloworld.fs

#! /usr/bin/env gforth
.( Hello, world!)
CR
bye

а также helloworld2.fs

#! /usr/bin/env gforth
S" Hello, world!" type
CR
bye

Насколько я могу сказать, синтаксис S" Hello, world" создает новую строку в некоторой глобальной области внутри среды выполнения Forth и помещает указатель на нее в стек. Это также может быть более богатый объект, чем этот, я не знаю, использует ли Форт строки с нулевым символом в конце.

В любом случае, gforth предоставляет некоторые слова для вызова функций C, здесь в hello_world_c.fs

#! /usr/bin/env gforth
\c #include <stdio.h>
c-function printf- printf a -- n

S" hello" printf-
CR

bye

Я ожидаю, что этот скрипт будет печатать hello а затем новая строка при запуске. Прототип для функции printf является a -- n... то есть он принимает адрес и возвращает что-то с тем же размером, что и int, Одна строка формата определенно является приемлемой коллекцией аргументов для передачи printf,

Тем не менее, он выдает ошибку:

$ ./hello_world_c.fs
ar: `u' modifier ignored since `D' is the default (see `U')

in file included from *OS command line*:-1
hello_world_c.fs:5: Invalid memory address
S" hello" >>>printf-<<<
Backtrace:
$7F3A14D65018 call-c
$763A14D64F50 execute

Я предполагаю, что проблема здесь заключается в том, что S" hello" на самом деле не указатель, а на самом деле что-то еще. Есть ли способ преобразовать его в указатель, поэтому вызов printf укажет на правильную вещь?

2 ответа

Как выясняется S" не создает строку с нулевым символом в конце и не только помещает адрес в стек.

S" создает временное местоположение (которое, по-видимому, живет по крайней мере до следующего вызова S") и помещает длину и адрес в стек.

После S" называется длина находится на вершине стека, этот порядок важен.

Вот пример интерактивного сеанса с gforth, с комментариями и подсказкой (>) вставлено для наглядности.

$ gforth
> S" a"                  ( define a new string, push length and addr )
> .s                     ( display size of stack and contents of stack )
<2> 22565888 1
> .                      ( print and drop top item of stack ) 
1
> .s                     ( display size and contents of stack again )
<1> 22565888
bye 

Слово s\" как S", за исключением того, что он соблюдает экранирование строки в стиле C. Он похищает "читателя" так же, как S" делает, но выполняет некоторый перевод.

Учитывая все это, вот реализация сценария, который призывает printf- правильно.

#! /usr/bin/env gforth

\c #include <stdio.h>
c-function printf- printf a -- n

( synonym for drop for documentation purposes.
  remove the initial length of a length, bytes pair created by
  S" or s\" )
: drop-cstr-length drop ;

s\" hello world\n\0" drop-cstr-length
printf-

bye

который печатает hello world и затем выходит нормально.

Обычно в Форте это можно упростить, создав новое слово, которое компилирует нужный вам код; что-то вроде этого:

      : cstr"   postpone s\"  postpone drop ; immediate

Тогда его станет проще использовать;

      #! /usr/bin/env gforth

\c #include <stdio.h>
c-function printf- printf a -- n

cstr" hello world\n\0" printf-
Другие вопросы по тегам