2

我正在printf使用S" ..."字符串调用 C 函数,但遇到了无效的内存地址。将指向在 Forth 端创建的以空字符结尾的字符串的指针传递给 C 的正确方法是什么?

这是 hello world in 的两个版本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 运行时的某个全局区域中创建了一个新字符串,并将指向它的指针压入堆栈。它也可能是一个比这更丰富的对象,我不知道 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在运行时打印然后换行。该函数的原型printfa -- 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将指向正确的东西?

4

1 回答 1

3

事实证明,S"它不会创建以 null 结尾的字符串,也不会专门将地址压入堆栈。

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然后正常退出。

于 2018-08-13T02:21:51.530 回答