gforth вызвать функцию 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 указывал на нужную вещь?


person Gregory Nisbet    schedule 11.08.2018    source источник


Ответы (1)


Как оказалось, 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, а затем нормально завершает работу.

person Gregory Nisbet    schedule 13.08.2018
comment
Глядя на спецификацию ANS Forth ( complang .tuwien.ac.at/forth/ansforth-cvs/documents/html3/core/), разве это не должно быть \z, а не \0? - person Max Barraclough; 07.03.2021