fc2ブログ

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

プロフィール 

高木信尚

Author:高木信尚

ホームページ
ブログ

最近の記事 

最近のコメント 

最近のトラックバック 

月別アーカイブ 

カテゴリー 

ブロとも申請フォーム 

この人とブロともになる

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

 

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フィード 

リンク 

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

Copyright(C) 2006 TAKAGI Nobuhisa All rights reserved.
Powered by FC2ブログ. template designed by 遥かなるわらしべ長者への挑戦.