目次
はじめに
はじめに
Visual C++ 2010 Expressのインストール
プログラムの作成
hello.c
コンパイルと実行
C言語プログラミングの学習環境
終了ステータスって?
整数値を3桁区切りで表示するプログラム
課題1 「整数値を3桁区切りで表示する」
ソースコードの雛形
h20a6.c
ソースコードの解説
配列の要素を反転する
課題2 「整数型の最大値と最小値を表示する」
h20a6_min.c
ソースコードの解説
課題3 「64ビットの整数値を表示する」
h20a6_x64.c
ソースコードの解説
他の言語のlong型
課題4 「整数値を4桁区切りの16進数で表示する」
h20a6_hex.c
ソースコードの解説
多倍長整数の加算を行うプログラム
課題1 「多倍長整数型を作る」
ソースコードの雛形
h21a9_set.c
ソースコードの解説
課題2 「多倍長整数の比較を行う」
h21a9_cmp.c
ソースコードの解説
課題3 「多倍長整数の加算を行う」
h21a9_add.c
ソースコードの解説
条件演算子を使用する
課題4 「多倍長整数の減算を行う」
h21a9_sub.c
ソースコードの解説
課題5 「多倍長整数型に符号を追加する」
h21a9_ssub.c
ソースコードの解説
課題6 「符号付き多倍長整数の加減算を行う」
h21a9_sign.c
h21a9_sign.c - part2
ソースコードの解説
数当てゲームを行うプログラム
課題1 「重複のない4桁の乱数を生成する」
ソースコードの雛形
h18a6_prev.c
ソースコードの解説
擬似乱数って?
課題2 「マスターマインドを作成する」
ソースコードの雛形
h18a6.c
ソースコードの解説
課題3 「平均推測回数を表示する」
h18a6_average.c
ソースコードの解説
課題4 「組合せを用いてマスターマインドを解くAIを作成する」
h18a6_ai.h
h18a6_ai.c
h18a6_ai_comb.c
ソースコードの解説
課題5 「順列を用いてマスターマインドを解くAIを作成する」
h18a6_ai_perm.c
ソースコードの解説
課題6 「順列のみを用いてマスターマインドを解くAIを作成する」
h18a6_ai_perm10.c
ソースコードの解説
ソースコードの分割
文字列のURLエンコードを行うプログラム
課題1 「URLエンコードを行う」
ソースコードの雛形
h16a6.c
ソースコードの解説
ポインタを扱うときの注意
課題2 「空白文字を+記号に置換する」
h16a6_space.c
ソースコードの解説
課題3 「URLデコードを行う」
h16a6_decode.c
ソースコードの解説
相対パスを絶対パスに変換するプログラム
課題1 「UNIX形式のパスを変換する」
ソースコードの雛形
h21h9.c
ソースコードの解説
課題2 「Windows形式のパスを変換する」
h21h9_win.c
ソースコードの解説
課題3 「両方の形式を変換する」
h21h9_both.c
ソースコードの解説
WindowsでもUNIXでもコンパイルできるソースコード
課題4 「ファイルの有無を確認する」
h21h9_exists.c
ソースコードの解説
標準ライブラリ関数の調べ方
単語幅でワードラップを行うプログラム
課題1 「単語幅でワードラップする」
ソースコードの雛形
h17h6.c
ソースコードの解説
課題2 「文字列をトークン分割する」
h17h6_token.c
ソースコードの解説
課題3 「改行文字に対応する」
h17h6_newline.c
ソースコードの解説
Windowsのフォントから文字幅を取得してみる
文字数でワードラップを行うプログラム
課題1 「文字数でワードラップする」
ソースコードの雛形
h22h9.c
ソースコードの解説
ファイル記述子って?
課題2 「タブ文字に対応する」
h22h9_tab.c
ソースコードの解説
課題3 「定義済みのキーワードを参照する」
ソースコードの雛形
h22h9_keyword1.c
ソースコードの解説
課題4 「キーワードを定義する」
h22h9_keyword2.c
ソースコードの解説
奥付
奥付

閉じる


<<最初から読む

18 / 120ページ

試し読みできます

ソースコードの解説

convert()

 関数convert()で64ビットの整数値を扱えるようにするための修正は、関数のシグネチャを 「void convert(long num, char str[])」から「void convert(long long num, char str[])」に修正するだけです。

バッファサイズの修正

 ただし関数convert()を呼び出す側にも注意が必要です。 64ビットの整数値を3桁区切り形式の文字列に変換すると、当然32ビットのときより長い文字列が出来上がります。 そのため関数convert()に渡す数字列バッファに十分なサイズがあるかを確認しておかなければなりません。
 変換する整数値がlong型のときは数字列バッファサイズを「#define BUFSIZE 15」としていました。 これは数字列が最長となるLONG_MINを変換した「-2,147,483,648」の14文字を格納できるサイズです。 long long型の場合はLLONG_MINを変換した「-9,223,372,036,854,775,808」の26文字が最長になりますから、数字列バッファサイズを「#define BUFSIZE 27」と修正しました。
 数字列バッファサイズは27以上であればいくつでも構いません。
試し読みできます

他の言語のlong型

Column : 他の言語のlong型

 「C言語のlong型は32ビットである」という表現は誤りで、正しくは「処理系によって異なる」と覚えなければなりません。 その処理系というのは64ビットOSのことだろうと単純に考えてしまいそうですけど、実はそれも正確ではありません。 なぜなら64ビットOSで64ビットに変わるのはメモリ空間(ポインタ型)であって、long型も64ビットに変わるかどうかは採用されているデータモデルによって異なるからです。
 Mac OS Xを含むUNIX系OSの64ビット版ではLP64(long型とポインタ型が64ビット)というデータモデルを採用しており、long型も64ビットに変わります。 しかしWindowsの64ビット版ではLLP64(long long型とポインタ型が64ビット)を採用しているため、long型は32ビットのままなのです。
 現在32ビット版ではUNIX系OSもWindowsもILP32を採用しています。 int型が16ビットしかなかったLP32はWindows 3.1時代のお話です。

データモデル


 このlong型のサイズが処理系によって異なるという事情はC++やObjective-Cでも同じです。
 ところがJavaでは「Javaのlong型は64ビットである」と言語仕様で決まっています。 OSのデータモデルに関わらずこのように決めてしまえる理由は、Java仮想マシンという別の処理系がOSとの間に入ってJavaプログラムを実行するという画期的な仕組みがあるからでしょう。
 C#でも「C#のlong型は64ビットである」と言語仕様で決まっています。 もう少し詳しく言うと「C#のlong型はSystem.Int64クラスの別名である」となっています。 C#にも共通言語基盤(CLI)という仮想マシンの概念があるため、System.Int64は他のOSへ移っても64ビットのままです。
 C++/CLIは共通言語基盤(CLI)上で動くプログラムを書くためにC++を拡張した言語仕様です。 「C++/CLIのlong型はSystem.Int32クラスの別名である」と決まっているので32ビットになります。
 Rubyは整数型を意識する必要のないスクリプト言語ですが、内部的にはFixnumクラスとBignumクラスが存在します。 Bignumは多倍長整数を扱うクラスで、演算結果がFixnumの範囲内か否かで自動的に相互変換が行われます。 そのFixnumの範囲が32ビットなのか64ビットなのかは「処理系によって異なる」です。
試し読みできます

課題4 「整数値を4桁区切りの16進数で表示する」

課題4 「整数値を4桁区切りの16進数で表示する」

 long long型の整数値を4桁区切り形式の16進数字列に変換するよう関数convert()を変更してください。 変換ルールは次の通りとします。
  1. 整数値を16進数に変換する。
  2. 負数の場合、先頭にマイナス符号を付ける。
  3. 16進数の下位から4桁ごとにスペースを挿入する。

4桁区切り形式の変換例

試し読みできます

h20a6_hex.c

  1. /** @file h20a6_hex.c
  2. * @brief 整数値を4桁区切りの16進数で表示するプログラム
  3. *
  4. * - 負数の場合、先頭にマイナス符号を付ける。
  5. * - 数値の下位から4桁ごとに空白を挿入する。
  6. * - LONG_MIN(-2147483648)の表示に対応する。
  7. * - 64ビットの整数値(LLONG_MAX, LLONG_MIN)に対応する。
  8. *
  9. * @see 平成20年度秋期 午後試験 問6
  10. */
  11. #include <stdio.h>
  12. #include <limits.h>


  13. /** 数字列バッファサイズ (64ビット対応) */
  14. #define BUFSIZE 27


  15. void convert(long long num, char str[]);


  16. /**
  17. * @brief 整数値から4桁区切りの16進数字列を生成する。
  18. *
  19. * @param [in] num 桁区切りしたい整数値
  20. * @param [out] str 桁区切りされた数字列
  21. * @return なし
  22. */
  23. void convert(long long num, char str[])
  24. {
  25. const char table[] = "0123456789ABCDEF";
  26. int minus = 1; /* フラグの使い方を変更 */
  27. int i = 0, j = 0;
  28. char tmp;
  29. /* 負数の場合、フラグを立てておく。 */
  30. if( num < 0 )
  31. {
  32. minus = -1;
  33. }
  34. do
  35. {
  36. /* 最下位桁を取り出し、16進数で1桁右シフトする。 */
  37. str[j++] = table[(num % 16) * minus]; /* 負数の対策 */
  38. num /= 16;
  39. /* 4桁ごとに空白を挿入する。 */
  40. i++;
  41. if( i % 4 == 0 && num != 0 )
  42. {
  43. str[j++] = ' ';
  44. }
  45. } while( num != 0 );
  46. /* 負数の場合、マイナス符号を付ける。 */
  47. if( minus != 1 )
  48. {
  49. str[j++] = '-';
  50. }
  51. str[j--] = '\0';
  52. /* 逆向きに出来上がった数字列を並べ直す。 */
  53. for( i = 0; i < j; i++, j-- )
  54. {
  55. tmp = str[i];
  56. str[i] = str[j];
  57. str[j] = tmp;
  58. }
  59. }


  60. /**
  61. * @brief エントリポイント
  62. *
  63. * @param [in] argc コマンドライン引数の数
  64. * @param [in] argv コマンドライン引数
  65. * @return 終了ステータス
  66. *
  67. * @par 実行方法:
  68. * cmd> h20a6_hex.exe
  69. */
  70. int main(int argc, char *argv[])
  71. {
  72. char buffer[BUFSIZE];
  73. long long test_data[] = {
  74. 1234567L,
  75. -57482L,
  76. 63L,
  77. -999999L,
  78. 0L,
  79. LONG_MAX,
  80. LONG_MIN,
  81. LLONG_MAX,
  82. LLONG_MIN
  83. };
  84. int t, tests = sizeof(test_data) / sizeof(*test_data);
  85. /* テストデータでconvert()を実行する。 */
  86. for( t = 0; t < tests; t++ )
  87. {
  88. convert(test_data[t], buffer);
  89. printf("%lld => %s\n", test_data[t], buffer);
  90. }
  91. return 0;
  92. }

試し読みできます

ソースコードの解説

convert()

 与えられた整数値numを16進数に変換するために関数convert()のループ処理を変更します。
 まず10進数で1桁ずつ取り出すための処理「str[j++] = table[(num % 10) * minus];」を「str[j++] = table[(num % 16) * minus];」に、「num /= 10;」を「num /= 16;」に書き換えました。 16進数に変換するなら「num % 16」、8進数に変換するなら「num % 8」、2進数に変換するなら「num % 2」を計算します。 これは午前試験レベルの知識ですので、プログラミングにも応用できるようにしておきましょう。
 あとは数値と数字の変換テーブルtable[]を16進数に対応できるように「const char table[] = "0123456789ABCDEF";」と拡張し、3桁ずつコンマを挿入していた処理を4桁ずつスペースを挿入する処理に書き換えれば変更は完了です。

整数値を4桁区切り形式の16進数字列に変換する処理


読者登録

nakano.hさんの更新情報・新作情報をメールで受取りますか?(読者登録について