So-net無料ブログ作成

あれの開発記 27ページ目 バグ? [ColdFire V1]

投票感謝キャンペーンは以下のアドレスで行っています。
http://hamayan.blog.so-net.ne.jp/2008-09-01-2
Img_0671.jpgなんかSilentCのポート番号の扱いにバグがあるかもしれない。

元々ポート番号は0~65535までの符号無し16bitの値を取るのだけれど、SilentCの場合はint型を使用している。
偶々なんだけれどポート番号40000をbindした相手先からパケットを送って、受け側ではこの様に処理してみた。


    if( (len = RecvFrom( soc, 10 )) == (-1) ) break;
    else if( len > 0 )
    {
      e_buf = GetReceiveBuffer( soc, 1 );
      r_ip = GetSenderIP( soc );
      r_port = GetSenderPort( soc );
      if( r_ip == dip && r_port == 40000 )
      {
        for( p = e_buf; len > 0; len-- )
        {
          if( *p == 0x1b )
          {
            MemoryFree( e_buf );
            CloseSocket( soc );
            return;
          }
          PrChar( *p++ );
        }
      }
      else

この中でr_port == 40000で引っ掛かってこの条件式は成立しなかった。そこでPrNumでr_portを表示させてみると(-25536)となってしまった。当然これでは一致しない。

元々このColdFireは32bitマイコンなのでint型も32bitと思われる(だよね)。だから正の整数の範囲に入っている40000はそのまま比較される筈。
ところがr_port = GetSenderPort( soc );の代入時には何処かで符号拡張が行われ、40000(0x9c40)は-25536として代入されてしまったのだろうと推測しております。



と言う訳で以下の様に直しました。
      r_port = GetSenderPort( soc );
      if( r_ip == dip && (r_port & 0xffff) == 40000 )

何故か
r_port = GetSenderPort( soc ) & 0xffff;
では(-25536)のままでした。



0xffffの扱いが気になったので、int型が32bitのBCC32で以下の実験を行ってみました。
#include 
void main( void )
{
  printf( "0xffff=%d\n", 0xffff );
  printf( "0x0ffff=%d\n", 0x0ffff );
  printf( "0xffffffff=%d\n", 0xffffffff );
  printf( "-1=%d\n", -1 );
}

結果は、
0xffff=65535
0x0ffff=65535
0xffffffff=-1
-1=-1

と、0xffffと0xffffffffはちゃんと区別してくれています。
何か間違っているのか?。実はint型は32bitではない?。

望洋さーん。

新版 明解C言語 入門編

新版 明解C言語 入門編

  • 作者: 柴田望洋
  • 出版社/メーカー: ソフトバンククリエイティブ
  • 発売日: 2004/08/28
  • メディア: 単行本



nice!(0)  コメント(7)  トラックバック(0) 

nice! 0

コメント 7

noritan

OS-1 プログラミングマニュアルによると、GetSenderPort( soc )が返すのは、intだそうです。これを r_port に代入すると r_port は、-25536 になります。

一方、 int 型の GetSenderPort( soc ) と int 型の 0xffff の論理積は、 int 型の -25536 のままで、これを r_port に代入すると -25536 になってしまいます。

(r_port & 0xffff) == 40000 が真になったことから、 r_port は long 型で、 0xffff も long 型として扱われたのではないかと推測します。

かといって、明示的なキャストや型指定定数などは記述できないようです。

すべて32-bitで書いてみてはどうでしょうか。
r_port = GetSenderPort( soc ) & 0x0000ffff;
by noritan (2008-09-03 08:55) 

hamayan

ああなるほど、明示的にffffの前に0を付ければ良いと。
by hamayan (2008-09-03 09:12) 

hamayan

と言うか、ちょっと焦点がずれそうなので補足しておくと、

まずbindする段階でもport番号はint型で扱われていますが、最終的にUDPヘッダーにコピーする所では符号無し16bitで扱われます。精度が落ちるのでもう元のデータが正なのか負なのか判らなくなり、CodeWarriorでは「本当にそんな代入して良いの?」と警告を受けるあれです。

逆に受けた符号無し16bit値をint型に何処かで変換していますが、その段階で符号拡張無しで変換してくれれば良いのですが、そうではないみたいなので、つまりユーザーはポート番号を-32768~32767の範囲で扱わなければならない。
「しかしこれはあれじゃあないですか?」と言う話です。

by hamayan (2008-09-03 09:33) 

noritan

つまり、「そもそも GetSenderPort( soc ) が 16bit の int を返してくるところがおかしい」というわけですね。

> 符号無し16bit値をint型に何処かで変換しています
int 型は 16bit なので、拡張なんかせずに、そのままコピーしていると思います。

# あれ?違う話をしているのかな?

by noritan (2008-09-03 12:37) 

hamayan

そうですね、適切な表現としたらunsigned shortではないでしょうか。ポート番号は負の値をとらないですし。
または精度を落とさずにポート番号を収容できる32bit int。

それよりも、SilentCのint型は一体16bitなのでしょうか、それとも32bitなのでしょうか?。てっきり32bitだと思っていたのですが。
プログラミングマニュアルの言語仕様はまだ出来ていないらしく、判らないのです。みんな困らないのかな?。

by hamayan (2008-09-03 12:57) 

noritan

PrHex(long)
PrHexWord(int)
PrHexByte(char)

と、並んでいるので、 int は、当然 16bit だと理解していました。

# もともとは、 S12NE64 という 16bit MCU 向けのインタプリタですから。

by noritan (2008-09-03 13:01) 

hamayan

ああナルホド、ライブラリから判断できるのか、、、。
てっきりコンピューターの自然な整数サイズだと思っていた。(※8bitは除く)

by hamayan (2008-09-03 13:07) 

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。