不同长度的 Fortran 子串比较问题
Problem with Fortran substring comparison of different length
我正在循环读取标准输入,并与一堆 "if" 进行比较,以根据输入决定要做什么。
这里是一段简短的代码:
CHARACTER (len= :), allocatable :: input
CHARACTER (len=4096) :: inbuffer ! frustrating but... well, fortran :3
DO
! get input
READ(*, '(a)') inbuffer ! because apparently you can't have allocation on read so you can't just read "input". meh.
input = TRIM(inbuffer)
CALL debug_log(input)
IF(input .EQ. 'uci') THEN
CALL debug_log(" printing uci info")
!isready
ELSE IF(input .EQ. 'isready') THEN
CALL debug_log(" isready -> readyok")
WRITE(*, '(a)') "readyok"
!ucinewgame
ELSE IF(input .EQ. 'ucinewgame') THEN
CALL debug_log("not implemented : reset board and start a new game")
!position
ELSE IF(input(1:8) .EQ. 'position') THEN
CALL debug_log("not implemented : set position")
!quit -> exit main loop
ELSE IF(input .EQ. 'quit') THEN
CALL debug_log(" quit command issued, exiting main loop")
EXIT
!non uci command
!nothing yet
!unknown command
ELSE
CALL debug_log(" ignoring invalid command")
END IF
end do
输入将期望像 "position 123 23415 etc..."
这样的命令
如果我输入 "posi",它会说这是预期的无效命令。
如果我输入 "position" 它说它也没有按预期实现。
但是:
- 如果我输入 "position":我没有执行
- 后跟 "posi":它表示 "not implemented" 而不是 "invalid command"
我的猜测是,即使输入只有 4 个字符,它也会读取 8 个字符,并且由于之前的命令是 "position",所以 position + tion = position
这里有一些日志来演示:
** opening debug file : 20181111 / 223418.127
223418.127 : Initializing Fortiche engine
223418.129 : Entering main loop
223420.859 : posi
223420.859 : ignoring invalid command
223426.467 : xxxxtion
223426.467 : ignoring invalid command
223430.498 : posi
223430.498 : not implemented : set position
223437.323 : xxxxxxxxx
223437.323 : ignoring invalid command
223439.418 : posi
223439.418 : ignoring invalid command
223443.979 : position
223443.979 : not implemented : set position
223447.122 : quit
223447.122 : quit command issued, exiting main loop
223447.122 : closing, bye
xxxxtion + posi = 位置
这显然是错误的,但我能理解它是如何结束的。
我应该使用 .EQ. 以外的东西吗?
当我打印输入时,它显然不会打印输入+内存中留下的任何垃圾。但它在比较可能不同长度的字符串时会这样做。
我该怎么做才能解决这个问题?
我什至没有开始使用硬核解析,但我已经遇到了问题。
我在 Windows 上使用 GNU Fortran。
是的,它是作为通用国际象棋界面的 UCI 东西。
编辑:完整源代码:https://github.com/ker2x/fortiche(评论第 107 和 108 行的脏黑客以重现问题)
子字符串引用的起始和结束位置必须在字符串的范围内。
您不防御在子字符串引用 input(1:8) .eq. 'position'
.
之前长度小于 8 的字符串
输入少于八个字符时,您的程序是不合格的,然后任何事情都可能发生,其中任何事情都非常合理地包含您看到的行为。
运行时调试选项可能有助于捕获此编程错误,具体取决于您的编译器的功能。
我正在循环读取标准输入,并与一堆 "if" 进行比较,以根据输入决定要做什么。
这里是一段简短的代码:
CHARACTER (len= :), allocatable :: input
CHARACTER (len=4096) :: inbuffer ! frustrating but... well, fortran :3
DO
! get input
READ(*, '(a)') inbuffer ! because apparently you can't have allocation on read so you can't just read "input". meh.
input = TRIM(inbuffer)
CALL debug_log(input)
IF(input .EQ. 'uci') THEN
CALL debug_log(" printing uci info")
!isready
ELSE IF(input .EQ. 'isready') THEN
CALL debug_log(" isready -> readyok")
WRITE(*, '(a)') "readyok"
!ucinewgame
ELSE IF(input .EQ. 'ucinewgame') THEN
CALL debug_log("not implemented : reset board and start a new game")
!position
ELSE IF(input(1:8) .EQ. 'position') THEN
CALL debug_log("not implemented : set position")
!quit -> exit main loop
ELSE IF(input .EQ. 'quit') THEN
CALL debug_log(" quit command issued, exiting main loop")
EXIT
!non uci command
!nothing yet
!unknown command
ELSE
CALL debug_log(" ignoring invalid command")
END IF
end do
输入将期望像 "position 123 23415 etc..."
这样的命令如果我输入 "posi",它会说这是预期的无效命令。
如果我输入 "position" 它说它也没有按预期实现。
但是:
- 如果我输入 "position":我没有执行
- 后跟 "posi":它表示 "not implemented" 而不是 "invalid command"
我的猜测是,即使输入只有 4 个字符,它也会读取 8 个字符,并且由于之前的命令是 "position",所以 position + tion = position
这里有一些日志来演示:
** opening debug file : 20181111 / 223418.127
223418.127 : Initializing Fortiche engine
223418.129 : Entering main loop
223420.859 : posi
223420.859 : ignoring invalid command
223426.467 : xxxxtion
223426.467 : ignoring invalid command
223430.498 : posi
223430.498 : not implemented : set position
223437.323 : xxxxxxxxx
223437.323 : ignoring invalid command
223439.418 : posi
223439.418 : ignoring invalid command
223443.979 : position
223443.979 : not implemented : set position
223447.122 : quit
223447.122 : quit command issued, exiting main loop
223447.122 : closing, bye
xxxxtion + posi = 位置
这显然是错误的,但我能理解它是如何结束的。
我应该使用 .EQ. 以外的东西吗? 当我打印输入时,它显然不会打印输入+内存中留下的任何垃圾。但它在比较可能不同长度的字符串时会这样做。
我该怎么做才能解决这个问题?
我什至没有开始使用硬核解析,但我已经遇到了问题。
我在 Windows 上使用 GNU Fortran。
是的,它是作为通用国际象棋界面的 UCI 东西。
编辑:完整源代码:https://github.com/ker2x/fortiche(评论第 107 和 108 行的脏黑客以重现问题)
子字符串引用的起始和结束位置必须在字符串的范围内。
您不防御在子字符串引用 input(1:8) .eq. 'position'
.
输入少于八个字符时,您的程序是不合格的,然后任何事情都可能发生,其中任何事情都非常合理地包含您看到的行为。
运行时调试选项可能有助于捕获此编程错误,具体取决于您的编译器的功能。