ymaeda_opentoolsを用いたプログラミングガイド

(Programming guide usingymaeda_opentools)


ymaeda_opentoolsでは 端末やシェルスクリプトから実行可能なコマンドも多数用意していますが、 それ以外にC言語の関数や構造体なども多数用意しています。 それらを用いれば本来のC言語よりも簡単にプログラミングを行うことができます。 そのための完全なマニュアルは ヘッダファイルのマニュアル に記載していますが、主なポイントを以下で説明します。
In addition to the numerous commands that can be executed from terminals or shell scripts, ymaeda_opentools consists of various C functions and structures. Using them, users can develop their original C programs more easily than without using these functions and structures. A complete documentation for the programming is available from the documentation of header files. Below, some of the points for the programming are described.


◆ヘッダファイルのインクルード (Including header files)

ymaeda_opentoolsを用いたCプログラミングでは冒頭にただ1行
#include <inc.h>
と書くだけで必要なヘッダファイルがほぼ全てインクルードされます。 通常のCプログラムで用いるstdio.hやmath.hなどのインクルードは プログラムに明示的に書く必要はありません。 inc.h経由でインクルードされるヘッダファイルの一覧は inc.hのマニュアルに書かれています。
Whenever you develop a C program with ymaeda_opentools, you need to write only one line
#include <inc.h>
at the head of the program. Almost all other header files are then included automatically. You do not need to explicitly write including header files that are often used, for example stdio.h or math.h, as they are included from inc.h. A full list of header files included through inc.h is available from the documentation of inc.h.


◆定数の利用 (Use of constants)

ymaeda_opentoolsではよく使う定数の多くをマクロとして定義しています。 例えば円周率を表すpi、文字列を表すchar型変数配列に標準的に用いる長さstrsize、 小さな実数を0と見なす閾値ZERO_THRESHOLDなどがあります。 これらはymaeda_opentools内の至るところで用いられており、 ユーザが独自にプログラミングをする際にも利用できます。 ymaeda_opentoolsで利用可能なマクロの一覧は こちらの索引から確認できます。
Frequently used constants are defined as macros in ymaeda_opentools; for example, pi that represents the circular constant, strsize used as the standard length of char-type arrays for strings, and ZERO_THRESHOLD used as the threshold value to regard a small real number as being zero. They are extensively used throughout the existing codes of ymaeda_opentools and can also be used by the users in their original code. A full list of macros defined by ymaeda_opentools is available from this index.


◆メッセージの出力経路の設定と表示 (Setting and displaying the message output route)

コンピュータプログラムを作成して動かすと様々なエラーが起きるものです。 エラーメッセージがプログラムのどの部分から出力されたものなのかを 容易に特定できる仕組みがあればエラーの解決が容易になります。
Occurrence of various errors is common in developing and testing a computer program. If the location of the origin of the error message is identified easily, the error can be fixed easily.

この目的のため、ymaeda_opentoolsのソースコードでは sRoute, rRoute, pRouteという3つのマクロを多用しています。 それらの実体は関数setMsgRoute, removeMsgRoute, printMsgRoute (いずれもmsg.h)です。 関数を呼び出す直前には必ず
sRoute;
と書くようにします。関数の呼び出しの直後には必ず
rRoute;
と書きます。そしてエラーメッセージを出力する箇所の直前には必ず
pRoute;
と書いておきます。 これにより、そのメッセージがプログラムのどの関数の何行目から どこを経由して表示されたのかがエラーメッセージに含まれるようになり、 エラー箇所の特定が容易になります。
For this purpose, three macros sRoute, rRoute, and pRoute are used extensively throughout the source codes of ymaeda_opentools. They represent functions setMsgRoute, removeMsgRoute, and printMsgRoute, all of which are in msg.h. Whenever you call a function, write
sRoute;
immediately before and
rRoute;
immediately after the function call. Whenever you write a code to display an error message, write
pRoute;
immediately before it. Then the error message will consist of the origin of the message (i.e., from and through what line of which function the message was displayed), which easens fixing the error.

例えば以下のサンプルプログラムのようにします。
For example, see the sample program below.

(sample.c)
#include <inc.h>

void sub1(void);
void sub2(void);
void sub3(void);

#include "sample_sub1.h"
#include "sample_sub2.h"
#include "sample_sub3.h"

int main(void)
{
    sRoute;
    sub1();
    rRoute;
    return 0;
}

(sample_sub1.h)
void sub1(void)
{
    sRoute;
    sub2();
    rRoute;
}

(sample_sub2.h)
void sub2(void)
{
    sRoute;
    sub3();
    rRoute;
}

(sample_sub3.h)
void sub3(void)
{
    pRoute;
    printf("エラーが発生しました。\n");
    printf("An error occurred.\n");
    exit(1);
}

このプログラムを実行すると以下のメッセージが表示されます。
次のメッセージは以下の経路をたどって表示されました。
ファイル"sample.c"第14行(関数"main")
->ファイル"sample_sub1.h"第4行(関数"sub1")
->ファイル"sample_sub2.h"第4行(関数"sub2")
->ファイル"sample_sub3.h"第4行(関数"sub3")
エラーが発生しました。
これにより、単に「エラーが発生しました」と表示されるよりも 原因の特定が容易になります。
This program shows the following message.
The message below is displayed through the following route:
File "sample.c" line 14 (function "main")
->File "sample_sub1.h" line 4 (function "sub1")
->File "sample_sub2.h" line 4 (function "sub2")
->File "sample_sub3.h" line 4 (function "sub3")
An error occurred.
This message is more useful to fix the error than displaying only the “An error occurred.” message.


◆2つの実数を簡単に比較する (Easily compare two real numbers)

実数には丸め誤差があるため
if((1.0/3.0)∗3.0==1.0){
    処理;
}
のようなif文や
double x;
for(x=0.1;x<=1.0;x+=0.1){
    処理;
}
のようなfor文は意図通りに動かない場合があります。 丸め誤差がプログラムの挙動に影響しないように
if((1.0/3.0)∗3.0>0.999999 && (1.0/3.0)∗3.0<1.000001){
    処理;
}

double x;
for(x=0.1;x<=1.01;x+=0.1){
    処理;
}
のような書き方をしなければなりません。
Rounding errors of real numbers may result in unexpected behaviour of an if-based branch:
if((1.0/3.0)∗3.0==1.0){
    (Processing);
}
or a for-based loop:
double x;
for(x=0.1;x<=1.0;x+=0.1){
    (Processing);
}
They should be written as:
if((1.0/3.0)∗3.0>0.999999 && (1.0/3.0)∗3.0<1.000001){
    (Processing);
}
or:
double x;
for(x=0.1;x<=1.01;x+=0.1){
    (Processing);
}
to avoid the unexpected behaviours.

ymaeda_opentoolsの 関数doublecmp (doublemath.h) を用いれば、より簡潔かつ直感的な書き方ができます。 この関数は2つの実数\(a\), \(b\)を比較して
を返します。但し\(a\), \(b\)に含まれる丸め誤差を考慮して、 \(a\)と\(b\)が完全一致でなくても「ほぼ同じ」ならば0を返す という仕様にしています。
Function doublecmp (doublemath.h) of ymaeda_opentools realizes a simpler and more intuitive coding. This function compares two real numbers \(a\) and \(b\), and returns
however, 0 is returned if \(a\) is “almost equal to” \(b\), even if they are not exactly equal.

関数doublecmpを用いれば上の例はそれぞれ
if(doublecmp((1.0/3.0)∗3.0,1.0)==0){
    処理;
}
および
double x;
for(x=0.1;doublecmp(x,1.0)<=0;x+=0.1){
    処理;
}
という書き方ができます。
Using the function doublecmp, the aforementioned examples can be rewritten as:
if(doublecmp((1.0/3.0)∗3.0,1.0)==0){
    (Processing);
}
and:
double x;
for(x=0.1;doublecmp(x,1.0)<=0;x+=0.1){
    (Processing);
}


◆実数から整数への変換を簡単に行う (Easily convert a real numbers to an integer)

実数の丸め誤差は整数への変換にも影響します。 例えば(1.0/3.0)×3.0を整数に変換したら1になるべきですが、 丸め誤差によって(1.0/3.0)×3.0=0.99999999…となり、 小数点以下を切り捨てることで0になってしまう場合があります。 これを避けるために
int i=floor((1.0/3.0)∗3.0+0.000001);
のような書き方が必要になります。
The rounding errors of real numbers also affect the results of conversions to integers. For example, (1.0/3.0)×3.0 should be converted to 1 but may become 0 by taking the integer part of (1.0/3.0)×3.0=0.99999999…. To avoid this situation, a code needs to be written in a way
int i=floor((1.0/3.0)∗3.0+0.000001);

ymaeda_opentoolsを用いればこのような面倒を避けることができます。 ymaeda_opentoolsの doublemath.h の中で、実数を整数に変換するための div2int, myfloor, myceil, myround という関数を用意しています。 これらはいずれも関数内で丸め誤差を考慮して変換が行われるため、 ユーザが明示的に丸め誤差対策を意識することなく変換を行うことができます。
This difficulty can be avoided by the use of ymaeda_opentools. Functions div2int, myfloor, myceil, and myround in doublemath.h of ymaeda_opentools converts a real number to an integer. As the rounding errors are taken into account in these functions, users do not need to explicitly consider the errors when they convert a real number to an integer using these functions.


●関数div2int (Function div2int)

割り切れることが分かっている2つの実数の間の割り算の結果を整数化する関数です。 例えば
int i=div2int(8.8,2.2);
と書けば8.8/2.2が計算されてi=4となります。 丸め誤差によって8.8/2.2が 4.00000000000001や3.99999999999999になった場合であっても div2intは正しく4を返すように設計されています。
This function divides a real number by another and converts the result to an integer. The numerator must be dividable by the denominator. For example,
int i=div2int(8.8,2.2);
computes 8.8/2.2 and returns i=4. Even if the result of 8.8/2.2 was 4.00000000000001 or 3.99999999999999 due to the rounding errros, the function correctly returns 4.


●関数myfloor (Function myfloor)

myfloorは実数の小数点以下を切り捨てて整数に変換する関数です。 例えばmyfloor(1.2)=1となります。
This function converts a real number to an integer by dropping the decimal part. For example, myfloor(1.2)=1.

C言語の組み込み関数のfloorでは機械的に小数点以下を切り捨てるので、 例えばfloor(0.99999999999999)=0となってしまいます。 一方、myfloorでは実数の丸め誤差を考慮に入れて 実数が最寄りの整数と「ほとんど差がない」場合には最寄りの整数を返します。 例えばmyfloor(0.99999999999999)=1となります。
The built-in C function floor simply drops the decimal part, resulting in floor(0.99999999999999)=0. The function myfloor takes into account the rounding errors and returns the nearest integer if the real number is “almost equal to” it. For example, myfloor(0.99999999999999)=1.


●関数myceil (Function myceil)

myceilはmyfloorとは逆に、 実数の小数点以下を切り上げて整数に変換する関数です。 例えばmyceil(1.2)=2となります。
This function converts a real number to an integer by modifying the decimal part to the larger-value side. For example, myceil(1.2)=2.

myceilもmyfloorと同様、実数の丸め誤差を考慮に入れます。 すなわち小数点以下を機械的に切り上げるのではなく、 実数が最寄りの整数と「ほとんど差がない」と見なせるか否かをチェックし、 ほどんど差がない場合は最寄りの整数を返します。 例えばmyceil(1.00000000000001)=1となります。
This function also considers the rounding errors, similar to the function myfloor. The decimal part is not simply modified to the larger side but instead first the real number is checked if it is “almost equal to” the nearest integer. If the answer was yes, the function returns the nearest integer. For example, myceil(1.00000000000001)=1.


●関数myround (Function myround)

myroundは実数の小数点以下を四捨五入して整数に変換する関数です。 例えばmyround(1.4)=1, myround(1.6)=2となります。 myroundも実数の丸め誤差を考慮に入れます。
This function rounds a real number to the nearest integer. For example, myround(1.4)=1 and myround(1.6)=2. This function also takes into account rounding errors.


◆日付・時刻の処理を簡単に行う (Easily treat dates and times)

C言語には日付・時刻を扱うためのstruct tm型構造体があります。しかし
といった点であまり使いやすくありません。
The C language has a built-in struct tm-type structure to treat a date and time. However, it is not convenient for use in that

そこでymaeda_opentoolsでは日付・時刻を表すための struct humanTime型構造体 を用意しました。 この構造体は
から成り、直感的にかつ1秒よりも細かい時間を扱うことができます。
In ymaeda_opentools, a struct humanTime-type structure is defined. It consists of:
This structure can treat the date and time intuitively and to a temporal resolution of less than 1 s.

struct humanTime型構造体を用いた日付・時刻の処理は mytime.h 内の関数を用いて簡単に行うことができます。 特によく使うのが humanTime_plus_sec, timecmp, timeStr2time の3つの関数です。
Processings of dates and times with the struct humanTime-type structures can easily be implemented using functions in mytime.h. Most frequently used functions are humanTime_plus_sec, timecmp, and timeStr2time.

関数timeStr2timeは日付・時刻を表す文字列を struct humanTime型構造体に変換する関数です。 例えば
struct humanTime dateTime=timeStr2time("2001/02/03","04:56:00.789");
のような使い方をします。 データファイルやコマンドラインオプションなどから読み込んだ日付・時刻を 構造体に簡単に格納できるので便利です。
The function timeStr2time converts strings that represent a date and a time to a struct humanTime-type structure. An example is:
struct humanTime dateTime=timeStr2time("2001/02/03","04:56:00.789");
Using this function, dates and times from a data file or command-line options can easily be preserved into the structure.

関数humanTime_plus_secは日付・時刻に指定した秒数を加算する関数、 timecmpは2つの日付・時刻を比較する関数です。 これらを用いれば日付・時刻に関するループ処理を簡単に書けます。 以下がその例になります。
The function humanTime_plus_sec increments a date and time by a specified length of time (s), and the function timecmp compares two date-times. Using these functions, a loop for date and time can easily be implemented, as the example below shows.

struct humanTime date_st={2019,1,1,0,0,0.0};
struct humanTime date_en={2022,12,31,0,0,0.0};
struct humanTime date_loop;
for(date_loop=date_st; timecmp(date_loop,date_en)<=0; date_loop=humanTime_plus_sec(date_loop,86400.0)){
    処理 (Processings) ;
}


◆組み込み関数をエラーチェック付きで実行する (Execute built-in functions with error checks)

C言語の多くの組み込み関数ではエラーチェックが行われません。 例えば関数sqrtを用いて 負の数の平方根(\(\sqrt{\hspace{0.5em}}\))を計算しようとしても エラーは出力されず、値がNaNとなるだけです。 その結果、例えばsqrtを用いた長大な計算コードによって 最終結果としてNaNが出力された場合に、 その原因がsqrtに負の数を代入したことにあると特定するのは容易ではありません。
Most built-in C functions does not check errors. For example, no error is issued by the calculation of the square root (\(\sqrt{\hspace{0.5em}}\)) of a negative value; instead, NaN is inserted in the result. Assume that you executed a large computation code including sqrt and it printed NaN as the final result. It is not easy to identify that the NaN caused from inserting a negative value to sqrt.

別の例として、関数atofでは文字列を実数に変換しますが、 元々の文字列が数値を表さない場合にもエラーは出力されず、 単に結果が0.0になってしまいます。 例えば第1引数(ARGV[1])で変数\(a\)の値、第2引数(ARGV[2])で変数\(b\)の値を取得して その和\(a+b\)を計算・出力するプログラムを書こうとして誤って
double a=atof(ARGV[0]);
double b=atof(ARGV[1]);
printf("%f\n"a+b);
と書いたとしても何のエラーも起きずに\(a=0\)として計算が行われてしまいます。 その結果、間違った計算結果を気づかずに得るリスクが高くなります。
Another example is function atof, which converts a string to a real number. No error is issued even if the original string does not represent a numerical value; instead, the function returns 0.0. For example, consider to develop a program that receives a variable \(a\) from the 1st argument (ARGV[1]) and another variable \(b\) from the 2nd argument (ARGV[2]) and computes the value of \(a+b\). Suppose that you took as mistake:
double a=atof(ARGV[0]);
double b=atof(ARGV[1]);
printf("%f\n"a+b);
Then no error is issued and the computation proceeds with \(a=0\). As a result, there is a high risk that a programmer may obtain a wrong computation result without being aware of it.

ymaeda_opentoolsの functions_with_errcheck.h にはC言語組み込み関数と同様の処理をエラー付きで実行する関数が定義されています。 例えば関数CKsqrtでは sqrtと同様に実数の平方根(\(\sqrt{\hspace{0.5em}}\))を計算しますが、 \(\sqrt{\hspace{0.5em}}\)の中身が負の場合には その場でエラーメッセージを出力してプログラムを終了します。 関数CKatofでは atofと同様に文字列を実数に変換しますが、 数値を表さない文字列を与えた場合には その場でエラーメッセージを出力してプログラムを終了します。 これらの関数を用いることで、 C言語組み込み関数をそのまま用いるよりも安全にコード開発ができます。
In functions_with_errcheck.h of ymaeda_opentools, functions are defined to perform the same processings as those of built-in C functions with error checks. For example, a function CKsqrt computes the square root (\(\sqrt{\hspace{0.5em}}\)) of a real number, just as function sqrt; however, if the content of \(\sqrt{\hspace{0.5em}}\) was negative, the function issues an error and the computation terminates immediately. A function CKatof converts a string to a real number, just as function atof; however, if the string does not represent a numerical value, the function issues an error and the computation terminates immediately. Using these functions, users can more safely develop their own codes than directly using the built-in functions.


◆ファイルの入出力と処理 (Reading, writing, and treating a file)

ymaeda_opentoolsでは ファイルを開く関数 CKfopen、 ファイルを閉じる関数 CKfclose、 およびこれらの関数で取り扱う FILE_L型構造体 を定義しています。 これらを用いることで、例えば
といった処理がファイルのオープンとセットで行われるので コード開発に当たってそれらのイレギュラー処理を意識せずに済み、 簡潔なコーディングが可能になります。
In ymaeda_opentools, functions CKfopen to open a file, CKfclose to close the file, and a FILE_L-type structure are available. Using them, a file is opened with, for example, the following checks:
Owing to these automatic processings for various irregulars, a programmer does not need to take care of these irregulars, which realizes a brief coding.

FILE_L型構造体はFILE ∗型(ファイルポインタ)のメンバmainを持ち、 ファイルの読み書きにはこのメンバを使用します。 典型的なコードは以下のようなものです。 ymaeda_opentoolsを用いない場合と異なる部分を赤字で示しています。
The FILE_L-type structure has a member main that is FILE ∗-type (a file pointer), which should be used for reading and writing a file. A typical code is as follows, where the red color indicates the differences between standard and ymaeda_opentools-based codes.

FILE_L fp;
int i=1,j;
fp=CKfopen("data.dat","w");
fprintf(fp.main,"%d\n",i);
CKfclose(fp);
fp=CKfopen("data.dat","r");
fscanf(fp.main,"%d",&j);
CKfclose(fp);

また、ymaeda_opentoolsの file.h にはファイルを簡単に取り扱うための関数が用意されています。例えば
などがあります。
Functions to treat files easily are defined in file.h of ymaeda_opentools. For example: