HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2019
0824
しまくろねこAndroid9上でのif文が正常に機能しない15解決


しまくろねこ

リンク

2019/8/24(Sat) 17:31:32|NO.88182

環境
HSP 3.6β1
Dish Helper 1.7
Windows10

上記環境で下記のコードを実行すると、Windows上では「OK」が表示されますが、Android9上だと「NG」が表示されます。
if文が正しく機能していません。


#include "hsp3dish.as" start_map_file = "web4_0.map" split_buff = "web4_1.map" if (start_map_file != split_buff) && (strlen(split_buff) > 0) { dialog "OK" } else { dialog "NG" } end



この記事に返信する


沢渡

リンク

2019/8/24(Sat) 19:24:24|NO.88184

なんとなくですが、if文よりもstrlenが怪しいような気がしますね。
文字コードの都合とか、Androidの仕様変更とかで、strlenの返り値が0になってしまう、とか?



しまくろねこ

リンク

2019/8/24(Sat) 20:04:11|NO.88186

dialog等を使用してstrlenの戻り値も確認しています。
strlenの戻り値は正常です。ちゃんと「10」が返ってきます。

書き忘れましたが、Android4の機種だとちゃんと「OK」になります。



しまくろねこ

リンク

2019/8/24(Sat) 21:06:46|NO.88188

試しに文字列比較の代わりに数値に変えたところAndroid9上で「OK」になりました。
文字列比較で引っかかっているのでしょうか?

#include "hsp3dish.as" a = 1 b = 2 split_buff = "web4_1.map" if (a != b) && (strlen(split_buff) > 0) { dialog "OK" } else { dialog "NG" } end
更にifを2つに別けて下記コードにしてみたところAndroid9上で「OK」になりました。
正常な動作ですが、NO.88182とほぼ同じコードなので謎です。
この場合文字列比較は正常だということです。

#include "hsp3dish.as" start_map_file = "web4_0.map" split_buff = "web4_1.map" if start_map_file != split_buff { if strlen(split_buff) > 0 { dialog "OK" } else { dialog "NG_1" } } else { dialog "NG_2" } end
しかし、この先

if (start_map_file != split_buff) && (strlen(split_buff) > 0) { dialog "OK" } else { dialog "NG" }
のようなコードを書くことがあると思いますので、できれば直して頂ければと思います。



Velgail

リンク

2019/8/24(Sat) 23:24:17|NO.88190

実機がないので何も言えませんが、バグの要因の切り分けが不十分でしたのでちょっとレスします。

なお、Windows Dishでの検証結果でバグ要因そうなのも見つけましたが、実機ではないので末尾に記載します。


if start_map_file != split_buff { if strlen(split_buff) > 0 { dialog "OK" } else { dialog "NG_1" } } else { dialog "NG_2" }

これが正常ということで、次のようなコードは失敗するのではないかという仮説を立ててみます。
2つの比較の論理和は失敗する説ですね。


if (5 != 10) && (10 > 0) { dialog "OK" } else { dialog "NG" }

値を整数で仮置してみました(値は実質何でも良いです)

もし、これがNGだとすれば完全にアウトですが…… どうでしょう?

これがOKであれば、次に

if (start_map_file != split_buff) && (10 > 0) { dialog "OK" } else { dialog "NG" }
で検証します。文字列比較 && 整数比較で死ぬ仮説ですね。

これがNGであれば、
if1=(start_map_file != split_buff)
if2=(strlen(split_buff) > 0)
の値を検証してください。

なお冒頭に書いたエラーの要因説になりうる話は、このif1とif2の値でして、それぞれ、-1, 1と異なる値になっていました。
なので、
if 1 && -1 でif文を定数で書いた結果、NGになった場合、この部分を踏み抜いたという説があります。



Drip

リンク

2019/8/25(Sun) 03:28:32|NO.88192

横から失礼します。Velgailさんも仰っている部分と少し被るのですが、
HSPでは文字列の比較で条件によってはマイナスを返す仕様(?)があるようで
比較結果を数式に使用したりすると想定外の結果がもたらされる場合があります。

通常、以下のスクリプトでは落ちません。(数値での比較)
kekka="偽","真"
hensuA=30 hensuB=30 hensuC=20 mes "hensuA == hensuB: "+kekka((hensuA==hensuB)) mes "hensuA == hensuC: "+kekka((hensuA==hensuC)) mes "hensuA != hensuB: "+kekka((hensuA!=hensuB)) mes "hensuA != hensuC: "+kekka((hensuA!=hensuC))
以下のスクリプトでも落ちません。(文字列での比較)
kekka="偽","真"
hensuA="abc" hensuB="abc" hensuC="ABC" mes "hensuA == hensuB: "+kekka((hensuA==hensuB)) mes "hensuA == hensuC: "+kekka((hensuA==hensuC)) mes "hensuA != hensuB: "+kekka((hensuA!=hensuB)) mes "hensuA != hensuC: "+kekka((hensuA!=hensuC))
しかし、以下のスクリプトでは落ちます。(↑と何が違うかな?)
kekka="偽","真"
hensuA="ABC" hensuB="ABC" hensuC="abc" mes "hensuA == hensuB: "+kekka((hensuA==hensuB)) mes "hensuA == hensuC: "+kekka((hensuA==hensuC)) mes "hensuA != hensuB: "+kekka((hensuA!=hensuB)) mes "hensuA != hensuC: "+kekka((hensuA!=hensuC)) //ここで落ちる
どうも文字列比較の場合、最初の不一致箇所のアスキーコードが比較元の値より
大きいか小さいかによって返す1の正負が入れ替わるようですが…
この現象を踏まえますと、しまくろねこさんのスクリプトでは
>if (start_map_file != split_buff) && (strlen(split_buff) > 0) {
if (-1 && 1) {
となりますよね。文字列の比較動作も含めこの解釈って大丈夫なのかしら?
などと漠然と不安を感じます。単純にマイナスが原因だった場合、
if abs(start_map_file != split_buff) && (strlen(split_buff) > 0) {
とすることで直るかと思いますが、この文字列比較においてマイナスを返す現象は
バグなのか仕様なのかはっきりさせたい所ではあります。

つい比較文を計算式に組み込むクセがある方は特に注意が必要です。
個人的には比較結果は0か1に統一してほしい気持ちですがいかがでしょうか?



しまくろねこ

リンク

2019/8/25(Sun) 08:26:07|NO.88193

>Velgailさん
ありがとうございます。

下記のコードは「OK」でした。

if (5 != 10) && (10 > 0) { dialog "OK" } else { dialog "NG" }
次のコードですが、
Android9では「NG」となりました。
Android4では「OK」となりました。

start_map_file = "web4_0.map" split_buff = "web4_1.map" if (start_map_file != split_buff) && (10 > 0) { dialog "OK" } else { dialog "NG" }
更に次のコードでは、
Android9では、if1が「-128」、if2が「1」という結果になりました。
Android4では、if1が「-1」、 if2が「1」という結果になりました。

start_map_file = "web4_0.map" split_buff = "web4_1.map" if1 = (start_map_file != split_buff) if2 = (strlen(split_buff) > 0) dialog if1 dialog if2

>Dripさん
なるほどです。
文字列の比較時には注意が必要ですね。
ありがとうございました。



Velgail

リンク

2019/8/25(Sun) 12:47:37|NO.88195

> しまくろねこ さん
状態回答ありがとうございます。

代替措置提案します

#define global ctype bool(%1) ((%1)!=0) #include "hsp3dish.as" start_map_file = "web4_0.map" split_buff = "web4_1.map" if bool(start_map_file != split_buff) && bool(strlen(split_buff) > 0) { dialog "OK" } else { dialog "NG" } end
面倒ですが、boolキャスト的な感じで使えるマクロ(#define global ctype bool...)を使うと、
常に整数値と0を比較して結果が0,1(か何か)になるので、こちらで条件式を括ってください。

少し面倒ですけどね……

(HSPの&演算子と&&演算子の混同は止めてほしいのですけどね……)



Velgail

リンク

2019/8/25(Sun) 14:30:03|NO.88196

まとめ

本件の要因は以下の通り。
1. if 文の判定
if 文は0をfalse, それ以外をtrueとして判定する。C言語と同等。

2. and/or演算子
HSPではビット積・ビット和演算しか提供されていない。論理和・論理積演算はない

3. strcmp演算(string比較部分)
比較結果が1,-1,-128など多彩な値が帰ってくる事が判明

よって、1よりifを分割すれば3の仕様は通るわけですが
2と3の仕様の相性が壊滅的に悪いということですね。

ちなみにabs(-128)&1→128&1=0なのでfalse,通りません。

論理和・論理積演算子の実装が待たれるところです。



しまくろねこ

リンク

2019/8/25(Sun) 14:57:40|NO.88197

>Velgailさん

まとめありがとうごます。



沢渡

リンク

2019/8/25(Sun) 17:40:07|NO.88198

HSP3DISHではない普通のHSPでも、「"ABCD"!="ABCd"」の結果は-1になるのですね。
比較演算の結果が0か1以外の数値になるとは、全く想像もつきませんでした。
strlenがどうとかトンチンカンなこと言って申し訳ありません。



Drip

リンク

2019/8/25(Sun) 19:04:20|NO.88199

Velgailさん

>3. strcmp演算(string比較部分)
>比較結果が1,-1,-128など多彩な値が帰ってくる事が判明
>ちなみにabs(-128)&1→128&1=0なのでfalse,通りません。

確かに、多彩な値が返ってくる場合はabsでは解決しませんね。
しかしながら私の確認している範囲ではこの現象が発生するのは
「文字列の不等価比較を行った場合」に限ります。
よって不等価比較を行わなければこの現象を回避できそうには見えます。
以下のように書くことでどのデバイスでも正常動作しないでしょうか?

start_map_file = "web4_0.map" split_buff = "web4_1.map" if (start_map_file = split_buff) | (strlen(split_buff) <= 0) { dialog "NG" } else { dialog "OK" }
ただ、不等価比較なしでプログラムを書きましょうというのは変な話なので
根本的な対応が待たれるところですが…;



Velgail

リンク

2019/8/25(Sun) 19:24:06|NO.88200

Dripさん

>しかしながら私の確認している範囲ではこの現象が発生するのは
>「文字列の不等価比較を行った場合」に限ります。

反例というかですが、次の場合も十分に発生します。

stick命令のReferenceより

stick a,0 ; 変数aにキー状態を読み出し if a&16 : goto *spc ; スペースが押されたか? if a&32 : goto *ent ; Enterが押されたか?

この場合、[Space]を押していて、かつ[Shift]を押しているか、といった場合に

stick mainkey,0 getkey isFire,16 if (mainkey&16)&&isFire : mes "Shift+Space"
同じような比較表現が現れてよくわからない不具合を招きます。

もちろん前述のboolマクロを利用しておけば
if bool(mainkey&16)&&bool(isFire) : mes "Shift+Space"
問題なく動作します。



Drip

リンク

2019/8/25(Sun) 22:00:54|NO.88201

Velgailさん

度々失礼致します。

>>しかしながら私の確認している範囲ではこの現象が発生するのは
>>「文字列の不等価比較を行った場合」に限ります。

>反例というかですが、次の場合も十分に発生します。

Velgailさんの説明は何に対する論説なのか意味がわかりません。
私の説明はしまくろねこさんが報告された問題の
文字列の不等価比較によって予測不可能な値が返って来る現象を
不等価比較を使わずに回避する方法を説明しています。
(この回避策では文字列の等価比較において0か1しか返らないようなので
 Velgailさんのbool判定は必要ないかと存じます。)

しかしながらVelgailさんは私の説明を引用しつつHSPが & と && を混同していることが原因で
引き起こされる数式の解釈の問題に関して深く言及しているように見えます。
(私はその件について全く言及していません。といいますのも、
 HSP2の時代からずっとそのようにHSPの仕様と理解しており、
 現在の標準HSPの & や && の振る舞いは現在の動作が正常であるという考えが前提で、
 今回のデバイス間で動作が異なる案件とは別件と捕らえております。)

それを前提でお話しますとVelgailさんの

>if (mainkey&16)&&isFire : mes "Shift+Space"
この式がよくわからない不具合を招くとのことですが、
これはHSPの仕様においてシフトキーとスペースキーの同時押し判定になりえるでしょうか。
stick命令においてスペースキーは16と検出され、isFireはシフトキーを1と検出します。
これまでのHSPにおいて ((16&16)&&1) や (16&&1) が真になることは有り得たでしょうか。
また本スレッドでAndroid9でのみその動作が変わるという報告がどこかにあったでしょうか。
(私の見落としがありましたら申し訳ありません。ご指摘をお願いいたします。)

>#define global ctype bool(%1) ((%1)!=0)
>if bool(mainkey&16)&&bool(isFire) : mes "Shift+Space"

こうしてしまうことで本来(16&&1)=0を判定したいところが(1&&1)=1を判定してしまい、
動作結果が変わってしまうかと存じます。

引用されましたので説明いたしましたが、ちょっと話の方向性がズレている気がします。
私はあくまでしまくろねこさんが仰っている問題の回避策に関して説明しています。
Velgailさんの話題はAndroid9での動作や文字列の不等価判定に関する話題の延長なのか、
それとも & と && の混同をやめてほしいという要望に関する話題なのか
前置きされたほうが混乱を避けられるかと存じます。
(ちなみに私個人的には&と&&の混同に別段問題や修正の必要性を感じておりません。
 本スレッドの趣向にそぐわなそうな話題なのでこれ以上言及する気はありませんが。)



おにたま(管理人)

リンク

2019/8/26(Mon) 21:04:42|NO.88212

HSP3Dishについてご報告ありがとうございます。
Android9とそれ以外で異なる結果になるのは初めて認識しました。皆様で色々な検証をして頂き感謝致します。
Android9の仕様というよりは、Android9からコンパイラとライブラリを変更したことが大きいかもしれません。何にしても、異なる実行結果になることは修正したいと思います。
Dripさんが指摘されたように、もともとHSPの仕様として、「文字列=文字列」の比較は0か1を返すのですが、「文字列!=文字列」はstrcmp関数の戻り値を返します。
なので、「文字列=文字列」の比較に修正することで今回のケースは回避されると思われます。
strcmp関数の戻り値は文字列ソートの際などには有用なのですが、ご指摘の通り&&などの論理演算子とは相性が良くないですね。今後のバージョンでの挙動について検討したいと思います。



Velgail

リンク

2019/8/26(Mon) 22:40:09|NO.88214

なんでこんな変なぶつかり方していたかようやく分かった。

C言語の&, |演算子を「ビット演算子」、&&, ||演算子を「論理演算子」と呼んでいる(そして、Java等もこちらで準拠)上でHSP上で論理演算子(実態がビット演算子)と言われると意図が伝わらなくなるというオチです。
はぁ……論理演算子がほしい。(VB.netでいうAndAlso, OrElse的短絡評価とともに)



ONION software Copyright 1997-2023(c) All rights reserved.