C99に対応した標準Cライブラリの実装レポートを行っていきます。

プロフィール 

Author:高木信尚

ホームページ
ブログ

最近の記事 

最近のコメント 

最近のトラックバック 

月別アーカイブ 

カテゴリー 

友達申請フォーム 

この人と友達になる

ホーム 全記事一覧 << 前の記事 次の記事 >>

 

2008/07/06 21:10|

 

strtol関数はlong型を返しましたが、strtoul関数はunsigned long型を返します。基本的な違いはそれだけです。細かな部分では、符号無し整数しか扱いませんので、'-'符号が現れるとそこで処理を終えますし、オーバーフローの判定はLONG_MAXではなくULONG_MAXで行います。

strtoull関数はunsigned long long型を返す関数ですが、strtoul関数とほとんど内容は同じですので、具体的な解説は割愛します。strtoul関数の実装のうち、unsigned longの部分をunsigned long longに、ULONG_MAXの部分をULLONG_MAXに読み替えれば、strtoull関数になると思います。

それでは、strtoul関数の実装です。

#include <limits.h>
#include <ctype.h>
#include <errno.h>

int _space_sign(const char *s, const char **endptr);

unsigned long strtoul(const char * __restrict__ s, char ** __restrict__ endptr, int radix)
{
  unsigned long result;

  if (_space_sign(s, (const char**)&s) != 0)
    --s;  // '-'の位置まで戻す

  if (s[0] == '0')
  {
    ++s;
    if ((s[1] | 0x20) == 'x')
    {
      if (radix == 0 || radix == 16)
      {
        ++s;
        radix = 16;
      }
    }
    else if (radix == 0)
      radix = 8;
  }
  else if (radix == 0)
    radix = 10;

  int c;
  for (result = 0; c = tolower((unsigned char)*s), isdigit(c) || ('a' <= c && c <= 'z'); s++)
  {
    int d = isdigit(c) ? c - '0' : c - 'a' + 10;
    if (d >= radix)
      break;
    if (result > (ULONG_MAX - d) / radix)
    {
      errno = ERANGE;
      result = ULONG_MAX;
    }
    else
    {
      result = result * radix + d;
    }
  }

  if (endptr != NULL)
    *endptr = (char*)s;

  return result;
}

細部を除けばstrtol関数と違いはありませんので、strtol関数と異なる部分だけ解説したいと思います。

まず、strtol関数では_space_sign関数の返却値をsignフラグに格納していましたが、strtoul関数では_space_sign関数が非0(=負)を返した場合は、ポインタを1つ戻し、'-'文字を指すようにしています。

次に、LONG_MAXを用いてオーバーロード判定を行っていた箇所は、ULONG_MAXを用いて判定しています。その際、signフラグによる補正もなくなっています。また、オーバーフロー発生時は常にULONG_MAXを返すようにしています。

最後に、signフラグがないため、結果はresultをそのまま返すようにしています。

2006/07/19 10:26|一般ユーティリティTB:0CM:2

コメント

直感とは、外れるが、strtoulは、'-'を受け取る。
http://anubis.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_006.html
マイケル #-|2006/08/06(日) 16:59 [ 編集 ]


マイケルさん、コメントありがとうございます。

この部分の解釈は難しいですね。
何度か規格を読み直したのですが、'-'を受け取った場合、errnoをERANGEに設定してULONG_MAXまたはULLONG_MAXを返すべきなのか、何事もなかったかのようにunsigned longまたはunsigned long longにキャストすればよいのかよくわかりませんでした。

規格では、「変換の結果の値は(返却値の型で)負数化したものとする」とありますが、「負数化」の定義がないので何ともいえません。
「新ANSI C言語辞典」でstrtoulのところを見ると、'-'は認識不能文字だとされているので、それを信じたのですが、既存の処理系を見ると、どれも'-'をそのまま受け取って、最後にunsigned longやunsigned long longでキャストしているようですね。

たかぎ #ftr86F3A|2006/08/11(金) 12:10 [ 編集 ]

コメントの投稿

管理者にだけ表示を許可する


トラックバック
トラックバックURLはこちら
http://libc.blog47.fc2.com/tb.php/78-e9162542

ホーム 全記事一覧 << 前の記事 次の記事 >>

ブログ内検索 

お勧め書籍 

RSSフィード 

リンク 

このブログをリンクに追加する

Powered By FC2ブログ 

Powered By FC2ブログ
ブログやるならFC2ブログ

Copyright(C) 2006 TAKAGI Nobuhisa All rights reserved.
Powered by FC2ブログ. 無料ホームページ アフィリエイト レンタルサーバー FC2ブログ 一戸建て template designed by 遥かなるわらしべ長者への挑戦.