Skip to content

Instantly share code, notes, and snippets.

@sasaki-shigeo
Last active June 30, 2025 16:03
Show Gist options
  • Save sasaki-shigeo/437ffaeb2c30ff02f2d82d5fee418355 to your computer and use it in GitHub Desktop.
Save sasaki-shigeo/437ffaeb2c30ff02f2d82d5fee418355 to your computer and use it in GitHub Desktop.
goto version of string to int

str2int.c に関する補足

  • ヘッダーファイル str2int.h が必要です。 #include "str2int.h" のように使ってください。
  • C言語で *(str++) というのは str[i++] のようなものです。
  • (c = str[i++]) != EOF
    1. str[i] を c に代入し
    2. i++ を実行し
    3. c の値が EOF に等しくないか比較します。
  • したがって while ((c = str[i++]) != EOF) { ... } は,「str から1文字ずつ取得しループする。EOF になったら終了。」という意味です。
  • オートマトンのプログラムを作る流儀はいくつかありますが,状態遷移とは,つきつめると gotoであり,gotoで移動しながら処理を進めるプログラムを示します。
    • 状態1つ1つに対応する gotoラベルを記載します。
    • gotoで状態遷移します。
    • 入力を受理したときの処理は次のいずれかの方法が考えられます。
      • 終了状態へ遷移する
      • returnで関数を脱出する
    • ここでは return文で脱出します。
    • 状態ごとの処理の先頭で1文字入力をします。

goto文を持たないプログラミング言語では,次の指針で, 同じようなプログラムをざっくり作れます。 String2int.java を参照してください。

  • 状態を表す型を定義します。(enum型が便利)
  • 入力列から1文字ずつ取得するループを作ります。
  • ループ内の switch 文で,状態の処理を担当する caseラベルにジャンプします。
  • 入力済みの文字に応じた処理をします。
  • 正常終了するときは returnで関数を脱出します。
  • 状態遷移は次を行います。
    1. 状態変数に遷移先の状態を代入
    2. continue
  • continue により次のように処理が進みます
    1. switch 文からの脱出(状態ごとの処理を終了)
    2. ループの先頭に戻る
    3. ループ処理の条件判定を実行; この際,同時に文字入力を進める
    4. switch 文で,次の状態のラベルへジャンプする
  • まとめると
    • プログラムの字面では,次の状態の代入と continue を行う
    • 実質的に,文字入力と次の状態へのジャンプが行われる

このプログラムでは「入力列」として Cの文字列を用いていますが, ファイルやそれを抽象化したストリームを「入力列」とするのが実用的です。 Java 版の String2int.java に,ストリームを入力列とするプログラムを示しました。

#include <stdlib.h>
#include <stdio.h>
#include "str2int.h"
long str2long(char *str) {
long result = 0;
int c;
START:
c = *(str++);
if (c == '\0') {
return 0;
}
else if (c == '0') {
goto ZERO;
}
else if ('0' <= c && c <= '9') {
result = c - '0';
goto DEC;
}
else {
return result;
}
ZERO:
c = *(str++);
if (c == 'x' || c == 'X') {
goto X;
}
else if ('0' <= c && c <= '7') {
result = c - '0';
goto OCT;
}
else {
return result;
}
DEC:
c = *(str++);
if ('0' <= c && c <= '9') {
result *= 10;
result += c - '0';
goto DEC;
}
else {
return result;
}
OCT:
c = *(str++);
if ('0' <= c && c <= '7') {
result *= 8;
result += c - '0';
goto OCT;
}
else {
return result;
}
X:
c = *(str++);
if ('0' <= c && c <= '9') {
result = c - '0';
goto HEX;
}
else if ('A' <= c && c <= 'F') {
result = c - 'A' + 10;
goto HEX;
}
else if ('a' <= c && c <= 'f') {
result = c - 'a' + 10;
goto HEX;
}
else {
return -1;
}
HEX:
c = *(str++);
if ('0' <= c && c <= '9') {
result *= 16;
result += c - '0';
goto HEX;
}
else if ('A' <= c && c <= 'F') {
result *= 16;
result += c - 'A' + 10;
goto HEX;
}
else if ('a' <= c && c <= 'f') {
result *= 16;
result += c - 'a' + 10;
goto HEX;
}
else {
return result;
}
ERROR:
fprintf(stderr, "internal error\n");
exit(1);
ACCEPT: /* use return result; instead goto ACCCEPT */
return result;
}
// data for testing
static char *literals[] = {
"0", "123", "077", "0xff", "0XFF",
NULL
};
// test function
int main(void) {
for (char **p = literals; *p != NULL; p++) {
printf("%s = %d\n", *p, str2int(*p));
}
exit(0);
}
extern long str2long(char *);
static inline int str2int(char *str) {
return (int)(str2long(str));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment