Вперед вызов функции 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-