始めまして。とびちよと申します。
イキバタ本でCを理解しようとwin98でBcc無料版を使ってやろうと思ってインストールして、取りあえず儀式のスクリプトを書いて、.c保存して
いざコンパイルだ!
と思い
c:\ctest>bcc32 hello.c
を打ちこみenterキーを押したところ、プロンプトに
コマンド、ファイル名が違います。
と表示されました。
いかせん初心者なもので、もしかすると、質問するにしては不備があるかもしれません。
なんとしても、この本で基盤を習得してしまいたいので、宜しくお願いします。
>「NULLが(void *)0と#defineされている処理系では、
> キャストしないとコンパイラワーニングが出る為」
んなアホな。ワーニングなんか見たことないですよ。
それに“K&R第2版 A6.8 voidへのポインタ”では
>ポインタは型void *のポインタへ、あるいはそうしたポインタから
>代入することが可能であり、それらと比較することもできる
とある通り、void *は特別な存在ですよ。ていうか“変なキャスト”を
予防する意味でvoid *は導入されたと個人的には思うのですが。
C++の場合はキャストしないとワーニングじゃなくてエラーになって
通過しないことがありますが、それと混同してるんじゃないですか?
その規約を書いた人は。
> FILE *f = fopen(...);
> if(f != (FILE *)NULL){
>
> としたほうがいいと堂々と雑誌の記事に書いたバカライターがいたけど
> この人の記事は最近見ないなー。
これも規約に堂々と書いてました。
「ポインタとNULLを比較する場合、必ず比較対象のポインタ型にキャストすべし」
と。続けてその理由として、
「NULLが(void *)0と#defineされている処理系では、
キャストしないとコンパイラワーニングが出る為」
とか書いてましたよ。
ホンマかいなと思って、
#define MY_NULL (void *)0
void hoge(void)
{
int x = 10;
int *p = &x;
if(p != MY_NULL)
printf("p is not NULL\n");
}
をコンパイルしてみましたが、何も言わなかったです。
ええ加減なこと書いとるな〜〜
> ...UNIXでそんなことしちゃいけませんってば。
> void main()で作った場合、そのprogramの終了コードは何になるんだろう?
コーディング規約で、「mainはvoid」とか書いときながら、
仕様書には、
「hoge処理が失敗したときは、更新したデータベースをロールバックし、
終了コードpiyoでexitすべし」
とか書いてますね。
で、その終了コードを呼び出し元のshellで見ているという・・・
何が何やらワケわからんです。
> プライベートヘッダファイルには、そのモジュール内で共通に使う型とか、
> そのモジュールのプライベート関数のプロトタイプ宣言などを書くと
> 思うんですが、そこで、パブリックヘッダファイルで宣言されている
> 列挙型やデータ受け渡し用の構造体などを使うことになりませんか?
使うこともあれば、使わないこともあるんじゃないでしょうか。
階層化されたソフトウェアの場合、プライベートヘッダファイルを
#include しているモジュールが呼ぶのは、より低レベルの非公開
モジュールだけであり、公開されているレベルのインターフェースは
全く必要としないということも、ままあるような気がします。
データ受け渡し用の構造体や共通関数は、くだんのプログラムでは、
より下位のレイヤで提供していて、それだけで独立したヘッダに
入っており、公開インターフェースには入っていませんでした。
あと余談ですけど、オブジェクト指向的設計を用いた場合、列挙型の
使用頻度は低くなりますよね。伝統的設計で列挙型を使うケースの
多くで、代わりに Factory クラスなどを使うことになるので。
(くだんのプログラムでは、それなりに列挙型も使ってますが。)
>他に「原則禁止」となってたのは・・・・
>(1)do〜while のループ
え?なんでだろう。もしも理由が、繰り返しの条件が先頭ではなく、おしりに
あるから、そこまで読みにいくのが面倒くさいから、だったらアホすぎですが。
>(char)NULL
ナイス!! そういや
FILE *f = fopen(...);
if(f != (FILE *)NULL){
としたほうがいいと堂々と雑誌の記事に書いたバカライターがいたけど
この人の記事は最近見ないなー。
>try {
>} catch (Exception ex) {
>;
>}
>
>で囲んで、例外を投げないようにしろ
あちゃあ!!これも聞いたことありますけど最悪ですね。
例外恐怖症とでも言うべきプロジェクトや会社はいくつかあるようですけど
例外を封じ込んだら例外の問題で頭を悩まさなくていいという主張でこうして
いるらしいですけど、目の前で犯罪行為が行われても誰も警察に通知しない
なら、犯罪はないのも同然だ、と言っているようで実に不愉快です。
粗雑とか言う以前に、こういうプロジェクトや会社はとっとと廃業すべきです。
> #define ZERO 0とかやっちゃう人もいる。
ありますね。
変わった#defineならこういうものも・・・
#define SPACE1 " "
#define SPACE2 " "
#define SPACE3 " "
#define SPACE1_LEN 1
#define SPACE2_LEN 2
#define SPACE3_LEN 3
私の関わった範囲ではSPACE50くらいまでありました。
使い方はmemcpyでコピーするだけです。
memset()+'\0'埋めの方が楽でしょうね。
荒技でsprintf(buf, "%*s", size, "")とか。;-)
> でも、lintフリーにすること自体は悪いことじゃないですよね。
もちろんです。:-)
ただプロジェクトをやっていると色んな人が入ってきて、
やはりというかキャストで誤魔化すだけの人が出てきてしまうので、
C言語を勉強しつつlintフリーにしないと大変になりますよね。
> どうなんでしょう。必ずしもそういうコンパイルオプションがあるとは
> 限りませんし、コンパイルオプションに頼らずどこでも動くのは悪い
> ことではないですし。
うーん。確かにコンパイラオプションを意識しないで済むのはメリットですね。
> # 昔、某巨大プロジェクトで、CHARがtypedefしてあって救われたことが
> # あったはず…
実際に助かったプロジェクトもあるんですかぁ・・・
要となるデータ型はtypedefでうまく隠しておいたほうが安全なんでしょうかね。
NULL=0の話じゃないですけど、typedefで隠しても
インクルードファイルの中を見て生のデータ型を書く人もいますよね・・・(^^;
>accが何者かわからないんですけど。
>Sunの提供しているccなら、-xchar=signedとか、-xchar=unsignedだったと思います。
accというのは、Sunが提供していたCコンパイラです。SunOSは
長いことK&R C(というか古いC)のコンパイラを積んでいたのですが、
ANSI C対応のCが出たとき、従来のものと区別するためaccと呼んでいました。
…そうか、今はaccじゃないのか… そういえばもう長いことSolaris
まともに触ってないなあ。
xcharオプションですけど、ちょっと検索してみたところによれば、
http://jp.sun.com/products/software/tools/fd602/documentation/mr/READMEs/c.html
この文書に「新機能」として載っていて、その文書の日付が
2001/06/20になっていますから、おおむねその頃に追加されたんでしょう。
つまりそれ以前はなかった、と。
>void main()で作った場合、そのprogramの終了コードは何になるんだろう?
>
>Cの規格じゃなくてUNIXかわの決まりだろうけど。
>たいていは0なのかな?不定?
昔、main()が終わったとき標準入出力バッファのフラッシュは誰が
やってくれるんだろうと疑問に思い、FreeBSDのスタートアップルーチンの
ソースを調べたら、
exit(main(argc, argv, env));
というようなことが書いてありました。
要するに、int型の戻り値だと思っているところにvoid型の関数を
リンクしたらどんな値が返っているように見えるか、ということで、
UNIX側の決まりというよりCコンパイラの仕様だと思います。
>#define ZERO 0とかやっちゃう人もいる。
#define CONST0 0
#define CONST1 1
#define CONST2 2
:
これに近いの見たことありますよ。
#define ErrorLevel1 1
#define ErrorLevel2 2
#define ErrorLevel3 3
:
これだともっとよく見るような。
>goto については、大規模な開発の場合、原則禁止にしておいた方が
>安全だと思います。もちろん例外脱出目的だと、特に問題ない利用法
>もあるわけですが、大規模開発だと必ず存在するダメ・プログラマに
>goto を許すと、保守不可能なプログラムを生産されてしまうので。
1関数が2000行くらいあって、gotoで戻ってcaseに飛び込んだりする
ソースをいじったことがありますが(;_;)
gotoでスパゲッティにしてしまうのは、goto云々以前に
「関数が長すぎる」というのがあるように思います。
関数が十分に短ければ、gotoで飛び回っても読める…というより
gotoを使う必要性が登場しないはず。
でもまあ、「1関数は何行以内」とルールで縛るのもちょっと無理が
ありますから、gotoを禁止するのが現実的な手かもしれません。
>> (3)extern宣言の使用
>まあ、確かに UNIX 上に限って言えば、ヘッダファイル中に extern 宣言
>なしで変数定義を書いても、それほど問題にならないんですが。
好意的に解釈すれば、
「グローバル変数は使用禁止。プログラムのあちこちから参照される
変数は、staticでそのソースファイル内に隠蔽して、get_xxx(),
set_xxx()という関数を付けろ」
という意味かも…
>これはそうだよな… と思い、例にひいたプログラムでどうしてたのか参照して
>みたんですが、そのプログラムでは、プライベートヘッダファイルから、
>パブリックヘッダファイルを、#include してませんでした。
>
>これで問題になるのは、.c ファイルでパブリックヘッダファイルの #include
>を忘れてしまい、関数プロトタイプ宣言を参照しない危険があるということ
>ですが、この危険については、常にコンパイラに警告を出させるようにして
>いるので、特に問題にはなってません。
プライベートヘッダファイルには、そのモジュール内で共通に使う型とか、
そのモジュールのプライベート関数のプロトタイプ宣言などを書くと
思うんですが、そこで、パブリックヘッダファイルで宣言されている
列挙型やデータ受け渡し用の構造体などを使うことになりませんか?
そうなると、パブリックヘッダファイルを#includeしないとコンパイルが
通らないことになるはずです。
> > lintフリーを謳っているところでした。
> でも、lintフリーにすること自体は悪いことじゃないですよね。
できるかぎりlint freeにした方がいいと思います。
lintよりgccの-Wallで警告なしにした方がいいと思いますが。
私は普段 gcc ...-Wall -Werrorにしてます。
lint freeにするために(void)printf()を
積極的に進める人と毛嫌いする人がいるんですけど
私は嫌いですねぇ。
printf()の返却値に関するlint messegeだけgrep -vで
はじいて見なかったことにしてます。:-P
> > ・charの符号は処理系依存なので、変数宣言では符号を明記する。
> > コンパイラスイッチで解決して欲しかった。;-<
> どうなんでしょう。必ずしもそういうコンパイルオプションがあるとは
> 限りませんし、コンパイルオプションに頼らずどこでも動くのは悪い
> ことではないですし。
> Solarisのaccのマニュアル
> からは、charが符号付きかどうかを制御するオプションは見つかりませんでした。
> 探し方が悪かったかもしれませんが。
accが何者かわからないんですけど。
Sunの提供しているccなら、-xchar=signedとか、-xchar=unsignedだったと思います。
> > もし組み込み系でないとすると、こんなのが規則で決まっている時点で、その
> > 規則を決めた人達に対する信頼度がゼロになりますね。
> え〜〜〜
> UNIXサーバ上で、TPモニタやら関係データベースと連携して動くシステムですね。
> ・・・ということは、某社の信頼度はゼロと(^^;;;
...UNIXでそんなことしちゃいけませんってば。
void main()で作った場合、そのprogramの終了コードは何になるんだろう?
Cの規格じゃなくてUNIXかわの決まりだろうけど。
たいていは0なのかな?不定?
っていうか、commandを組み合わせてshell scriptで何かやろうとしたら
終了statusって便利だし、UNIXで何かやろうとして開発したものって
何らかのscriptと組み合わせること多いんじゃないのかなぁ?
そしたら、mainがreturnで値を返さないと困ると思うんだけど。
常にexit(値)を呼んでるのかな?
ちなみにvoid main()に対して、lintは文句言わないのかなぁ?
> > もしターゲットが組み込み系の場合、スタックのサイズに制約があることが
> > 多いので、「原則」禁止というのも理解できなくはありません。
組み込みでは確かにstackの制限は厳しいのは確かですが(defaultが1024 Byteとか)
UNIXでMultiThread programなんかだと
threadごとにthreadを作る段階でstack sizeを指定しますよね?
既にあるMultiThread Programに
関数を追加するなんてことをした場合は、安全のために禁止してるとか。
全体を正しく把握できてない人がやったら
再現性のない結構ヤバメの不具合になるかも。
> > (つまり「原則」は禁止だが、再帰の最大の深さがあらかじめ分かる場合には
> > 許可すると…)
まぁ、でも普通は深さの見積もりって、ある程度はするもんじゃないんですかね。
WindowsやUNIXだって、無限にstackが詰めるわけじゃないし。
# いや、最近のPCは無限と思っていいくらいのmemory/HDDがあるかなぁ...
> memset(buf_piyo,(char)NULL,sizeof(buf_piyo));
数字は、そのまま書くんじゃなくて全てdefineしなくちゃいけないとか
言う決まりがあって、#define ZERO 0とかやっちゃう人もいる。
0はいいんじゃネェの?0は。(^^;)
仮に0という値に意味があるなら、ZEROはまずいだろうし。
呼ばれたような気がして‥‥何故って私はシグマプロジェクトの文化を
継承したシステムでの開発経験者だからです(笑)
といってもですね、実際私の目に触れたのは「その結果としてあるもの」で、
過去、シグマがどのような考え方で推進され、どのような問題で頓挫したのかまでは
残念ながらわかりません。
というわけでとりあえず、私が聞きかじったのと、実際に目にした結果から推測した
断片的な情報ですが、シグマって多分こんなものという話を。
どうやらシグマには「論理プロセッサ」という概念があったようです。(これは確か)
これはつまり、非常に単機能な処理系を論理的に規定した処理単位で、
今でいえばオブジェクトのようなもんでしょうか。
例えば「通信を制御するプロセッサ」とか「特定のデータを検索するプロセッサ」と
いったようなものを定義し、実際のハードにはその論理プロセッサの何をどう収容するか
という考え方でシステムを構築する。その論理プロセッサに定義された条件さえ
満たせば、どのようなハードでどのように実装してもよい、と。
そういった論理プロセッサの情報を実際にハードに実装した企業から
プロジェクトにフィードバックしてもらって、他のアーキテクチャでの実装に
役立てると。そういった経験を積み重ねていくと、そのうち全てのシステムは
どのプロセッサをどう組み合わせるのかといった、レゴブロックのような感じで
サクサク開発できてウハウハ、という発想がシグマだったと推測されます。
では、この皮算用がどうして破綻したかというと、まずシグマから支援を受けて
開発をした企業が、なんだかんだ理由をつけて、ソースコードの公開を拒んだこと。
まぁ、そりゃそうだろって感じです。実際にはいくらかの情報は戻してたんでしょうが
それも所詮「一応公開する気はある」というポーズにすぎなかったんじゃないかって
感じです。
それから、多分これが一番大きかったんだと思いますが、肝心要の「論理プロセッサ」
という考え方が、好き勝手に拡張され続けて収集がつかなくなったこと。
まぁ、いろんな会社が既存の論理プロセッサの解釈を自分の都合にのいいように
行ったため、現実的に集まったのは、名前は同じでもまったく似て否なるもの。
それに加えて、どうも論理プロセッサは必要に応じて順次増やされていくことに
なっていたらしく、既存の論理プロセッサでは開発の効率が悪そうだとなると、
各企業がいろいろ理由を付けてどんどんプロセッサを増やしていった。
その結果似たようなプロセッサや、特定のシステム以外にはまったく必要ない
プロセッサがポロポロできあがって、気がついたときには誰にも収集がつけられない
状態になってました、と、おそらくそんな話だったのではないかと思います。
だから「シグマOS」とは、このような考え方に沿った開発が行われた
(ことになっていた)OS、っつーかミドルウェア? VM? のこと?
を指すのであって、トロンのような具体的なシステムを指すものでは
ないのではないかと推測されます。
繰り返しになりますが、これは私が見聞きした非常に断片的な情報から
導いた、9割方はただの推測にすぎないので、
真に受けて恥をかいても知りませんよ。為念(笑)
土井さん wrote:
> 他に「原則禁止」となってたのは・・・・
> (2)gotoの使用
goto については、大規模な開発の場合、原則禁止にしておいた方が
安全だと思います。もちろん例外脱出目的だと、特に問題ない利用法
もあるわけですが、大規模開発だと必ず存在するダメ・プログラマに
goto を許すと、保守不可能なプログラムを生産されてしまうので。
> (3)extern宣言の使用
うーん、この原則はイカンです。
まあ、確かに UNIX 上に限って言えば、ヘッダファイル中に extern 宣言
なしで変数定義を書いても、それほど問題にならないんですが。
でも、変数の初期化忘れを防ぐためには、UNIX 上であっても、ヘッダ
ファイル中の変数宣言に必ず extern をつけた方が安全ですよね。
(ぱ) さん wrote:
> 本多さん wrote:
>>> ・charの符号は処理系依存なので、変数宣言では符号を明記する。
>> コンパイラスイッチで解決して欲しかった。;-<
> どうなんでしょう。
char の符号については、ソースプログラム中で明示的に unsigned char
を使うなり、あるいは typedef した型を使うなりした方が、スタイルと
しては良いと思います。少なくとも、UNIX 上で移植性の高いプログラムを
書こうと思ったら、必ずこうすべきです。
もっとも、そうすると、<string.h> などの関数を呼ぶときに必ず
(unsigned char *) というキャストが必要になって、かなり欝になるん
ですが… ;-<
> ある機能を提供する「モジュール」がひとつの.cファイルでは済まず
> 複数の.cファイルにわたる場合、「モジュールプライベートなヘッダファイル」
> が必要になり、プライベートヘッダファイルはパブリックヘッダファイルを
> #includeしなければいけませんから、
これはそうだよな… と思い、例にひいたプログラムでどうしてたのか参照して
みたんですが、そのプログラムでは、プライベートヘッダファイルから、
パブリックヘッダファイルを、#include してませんでした。
これで問題になるのは、.c ファイルでパブリックヘッダファイルの #include
を忘れてしまい、関数プロトタイプ宣言を参照しない危険があるということ
ですが、この危険については、常にコンパイラに警告を出させるようにして
いるので、特に問題にはなってません。
もう一つの問題は、.c ファイルが冗長になる (一つにまとめられる #include が
.c ファイルに分散してしまう) という点だと思います。
ところが、このプライベートヘッダファイルを #include している .c ファイル
群の中には、一つも公開関数を定義していない .c ファイルもあります。
(この .c ファイルでは、内部的に利用する非公開関数しか定義していないのです。
なぜそういう関数のために .c ファイルを分けているかというと、サブクラス
単位で .c ファイルを分けているから -- すなわち、そのサブクラスの関数の
ほとんどは、C++ でいうところの仮想関数ポインタ経由でしかアクセスされな
い [ただし、コンストラクタにあたる関数は仮想ではありません] から -- です。)
つまり、プライベート・ヘッダに #include <パブリック・ヘッダ> を書くと、
必要ないヘッダ・ファイルを #include することになり、逆の意味で冗長になる
こともあるように思います。
> いずれにせよネスト禁止では困るように思います。
Indian Hill coding style にある
>>>> ヘッダファイルのプロローグでは、このヘッダが機能するために他に
>>>> #include しなければならないファイルをあげておくべきである。
なんて規約を作るくらいなら、ネストを許した方が、むしろ現代的で良さ
そうだと思います。この規約がある理由としては、コンパイルがちょっと
遅くなるとか、Makefile の依存規則を手書きするのが面倒とかいった理由
しか思いつかないんですが、どちらも時代遅れな理由だと思うので。
他になにか理由ってありますかね?
でも、そもそも、「ヘッダが機能するために他に #include しなければならない
ヘッダというものが存在しない」ような設計方針もあり、そういう設計方針を
とっている場合は、ネスト禁止でも良いんじゃないでしょうか。
もっとも、くだんの会社のソフトウェアが、そういう設計方針で作られている
とは、あまり思えませんが。
むしろ、Indian Hill の受け売りをしているだけ?
元ネタ投稿者です。
表で盛り上がってたんですね・・・緊張します(^^;;
> ターゲットが、組み込み系プログラムってことはないですか?
> ANSI C でも、フリースタンディング環境の場合は、void main も許され
> ていると思います。
ご指摘ありがとうございます。
勉強になります。
> もし組み込み系でないとすると、こんなのが規則で決まっている時点で、その
> 規則を決めた人達に対する信頼度がゼロになりますね。
え〜〜〜
UNIXサーバ上で、TPモニタやら関係データベースと連携して動くシステムですね。
・・・ということは、某社の信頼度はゼロと(^^;;;
> どんな再帰プログラムも、ごく機械的な手続きで、配列を使ったループに
> 変換できますから。その方が実行性能もちょっと改善されるのが普通ですし。
>
> もっとも、ループに直すとソースコードの可読性は大幅に低下するので、
> 性能が非常に重要なところ以外では、普通、そんなことはしませんけど。
>
> もしターゲットが組み込み系の場合、スタックのサイズに制約があることが
> 多いので、「原則」禁止というのも理解できなくはありません。
> (つまり「原則」は禁止だが、再帰の最大の深さがあらかじめ分かる場合には
> 許可すると…)
>
> もし組み込み系でない場合は (以下略)
同じく某社の信頼度は(以下略)
ちなみに、「原則禁止」のワザを使うときは、
「主任技師の承認を得、ソースコードにコメントを残せば使ってもいいよ」
って書いてました。
他に「原則禁止」となってたのは・・・・
(1)do〜while のループ
(2)gotoの使用
(3)extern宣言の使用
ってなってました。
(1)はまぁ滅多に使わないので、ど〜でもいいです(ォィ)
(2)はどうかなぁ・・・・たまにエラー処理とかで使いたくなるかなぁ・・・
(3)については・・・・むぅ・・・・
最後に本日発見したトホホなコードを。
#define PIYO_SIZE 100
void hoge_hoge(void)
{
char buf_piyo[PIYO_SIZE];
memset(buf_piyo,(char)NULL,sizeof(buf_piyo));
/* 以下略 */
grep (char)NULL したら、数十カ所から発見されました。
鬱ですな・・・・
ではまた♪
> とにかく著作権の非常にゆるい国なんですな。
これはこれで大変に困ったことだと思うんですが、
> 著作権保護ばかり目が行って、何もできないでいる日本も問題ですよね。
これも困ったものだと思います。
ただ、音楽配信については、著作権云々だけじゃなく、小額決済の方法に
ついて決め手がないことも関係していると思います。
100円や200円払うためにクレジットカード番号を入れるのも嫌だし。
WebMoneyみたいなプリペイドカードも、だいぶポシャったようですし。
> ・すべての変数とメソッドに『public static』をつけろ。
どーしてもCOBOLerなプログラマしか集まらなかった場合には、
さっさとプログラムを作るためには、有効な規約かも。
> ・例外を出すメソッドはすべて『throws Exception』をつけろ。
...
> 後者は例外の考えが粗雑な人たちなんでしょう。深刻な例外で
> あろうが軽微な例外であろうが一律同じExceptionで片付けて
> しまえという乱暴さがにおってきて、ちょっと抵抗があります。
Javaの例外処理機構って、例外を厳密に処理させてくれるところが
便利だと思うんですけどねえ。
でも、メソッドは全部
try {
} catch (Exception ex) {
;
}
で囲んで、例外を投げないようにしろ、と言ってないだけマシですか(^^;
> ・関数呼び出し時に返却値を受け取らない場合、明示的に(void)をつける。
これ、Practical C Programmingという本が、第2版くらいまでこうなっていた
はずです。訳者の岩谷さんが例によって脚注で、これは変だと言ってたはず。
> lintフリーを謳っているところでした。
でも、lintフリーにすること自体は悪いことじゃないですよね。
> ・charの符号は処理系依存なので、変数宣言では符号を明記する。
> コンパイラスイッチで解決して欲しかった。;-<
どうなんでしょう。必ずしもそういうコンパイルオプションがあるとは
限りませんし、コンパイルオプションに頼らずどこでも動くのは悪い
ことではないですし。CHARとUCHARをtypedefしておく方がよいのは
確かでしょうが。
Solarisのaccのマニュアル
http://jp.sun.com/products/software/tools/fd602/documentation/mr/manpages/man1/acc.1.html
からは、charが符号付きかどうかを制御するオプションは見つかりませんでした。
探し方が悪かったかもしれませんが。
# 昔、某巨大プロジェクトで、CHARがtypedefしてあって救われたことが
# あったはず…
> ・longの符号は処理系依存なので、変数宣言では符号を明記する。
> 私はそんな処理系聞いたことないです・・・もしかして存在します?
私も聞いたことないです。あっても規格違反ですが。
いろいろご指摘ありがとうございます。
> ANSI C でも、フリースタンディング環境の場合は、void main も許され
> ていると思います。
ああ、それはそうですね。フリースタンディング処理系では、
そもそもmain()関数がなくてもいいわけですから。
> > 必要もないのに再帰を使うのはよくないと思いますが(階乗の計算
> > くらいループでできるだろうと)、木構造では避けられませんよね。
>
> 避けられないわけではないです。
> どんな再帰プログラムも、ごく機械的な手続きで、配列を使ったループに
> 変換できますから。その方が実行性能もちょっと改善されるのが普通ですし。
確かに。スタックを別の方法(配列など)で実現すれば可能ですね。
どうも私はやっぱり富豪的プログラミングが染み付いていて、組み込みなどの
方向に考えがが行かないようです (^^;
> 構造体へのポインタを抽象データ型として使う (ヘッダファイルでは、
> struct へのポインタだけ利用し、struct の実体は .c ファイルで定義
> する) スタイルを用いると、大きなプログラムでも、この原則に容易に
> 従うことができます。
これは、私も以下のページに書いてます。
http://member.nifty.ne.jp/maebashi/programmer/c_yota/module.html
よって、
> あるヘッダが機能するためには、普通別のヘッダファイルが
> たくさん必要になるので、
ってのは必ずしも「普通」じゃないですね。ぼけてました。
でも、「struct の実体は .c ファイルで定義する」のならいいんですけど、
ある機能を提供する「モジュール」がひとつの.cファイルでは済まず
複数の.cファイルにわたる場合、「モジュールプライベートなヘッダファイル」
が必要になり、プライベートヘッダファイルはパブリックヘッダファイルを
#includeしなければいけませんから、いずれにせよネスト禁止では困るように
思います。
> > ・main関数はvoidにすべし(ANSI規格って見たことありますか?)
ターゲットが、組み込み系プログラムってことはないですか?
ANSI C でも、フリースタンディング環境の場合は、void main も許され
ていると思います。
もし組み込み系でないとすると、こんなのが規則で決まっている時点で、その
規則を決めた人達に対する信頼度がゼロになりますね。
> > ・関数の再帰呼び出しは原則禁止(リストや木構造は使うなと)
>
> 必要もないのに再帰を使うのはよくないと思いますが(階乗の計算
> くらいループでできるだろうと)、木構造では避けられませんよね。
避けられないわけではないです。
どんな再帰プログラムも、ごく機械的な手続きで、配列を使ったループに
変換できますから。その方が実行性能もちょっと改善されるのが普通ですし。
もっとも、ループに直すとソースコードの可読性は大幅に低下するので、
性能が非常に重要なところ以外では、普通、そんなことはしませんけど。
もしターゲットが組み込み系の場合、スタックのサイズに制約があることが
多いので、「原則」禁止というのも理解できなくはありません。
(つまり「原則」は禁止だが、再帰の最大の深さがあらかじめ分かる場合には
許可すると…)
もし組み込み系でない場合は (以下略)
> > ・includeのネストは原則禁止(まさかMakefileを手作業で作っているとか?)
> あるヘッダが機能するためには、普通別のヘッダファイルが
> たくさん必要になるので、「多数の同じヘッダをインクルード
> しなければならないというような極端な場合」というのは極端でも
> なんでもなく、当たり前の状況だと思うんですが… はっきり言って
> 支離滅裂です。
今作っているプログラムは C で 4万行をオーバーしているんですが、
ほぼこの規則 (include がネストしない) に従っています。
ただ、意図してこうしたわけではなく、結果的にこうなりました。
構造体へのポインタを抽象データ型として使う (ヘッダファイルでは、
struct へのポインタだけ利用し、struct の実体は .c ファイルで定義
する) スタイルを用いると、大きなプログラムでも、この原則に容易に
従うことができます。このスタイルを使わない場合に別のヘッダを必要
とするような状況では、このスタイルを使うと「#include <別のヘッダ>」
の代わりに、「struct 別のヘッダで提供している構造体名;」を書くこと
で代用できます。
C++ だと pimpl と呼ばれるイディオムが、このテクニックにあたります。
(その場合、「class 別のヘッダで提供しているクラス名;」と書くことが
#include の代用になります。)
この種のスタイル/イディオムは、むしろ大規模なプログラムの方が有用
です。ただ、プログラムが malloc/new のかたまりになるので、組み込み
系には向きませんけど。
> コピーもできないという話以前に、曲がないんじゃどうしようもない。
> いや、私が不勉強でそういうサイトを知らないだけなのでしたら、
> ぜひとも教えて欲しいんですが。
私もあるなら教えて欲しいです。
以前、私も一生懸命探したのですが、目的の曲が見つからなかった。
その曲は後で手に入れたんですけどね。結局。
どこで手に入れたって、お隣の国韓国のWEB site。
そもそも日本の音楽を販売することが法律で禁止されているからCD自身も非合法。
非合法のものをcopyするなんてもちろん規制できないとか言う。
(いや、国内の合法のCDのcopyもあるから、どっちも規制できてないか)
日本の歌が何万曲ってあって、CD titleや歌手で自由に検索できるし。
唯一の弱点はハングルが入力できないとダメって言うこと。
あ、もう一つ、国民番号が必要だったかな。探すまではできたけど、
落とすのは友人に頼んだっけ。もちろん全部無料。非合法だし。
とにかく著作権の非常にゆるい国なんですな。
DVDとか映画の公開より先に格安で販売されてるし、
気に入った曲の入ったCDを買ったら、
「この国でCDなんか買っちゃダメですよ。全部タダでdown load可能なんだから」
とか言われちゃうし...(^^;)
全く保護してない国も問題ですが、
著作権保護ばかり目が行って、何もできないでいる日本も問題ですよね。
そういうsiteがないからWinMXとかWinnyとかが流行っちゃうのかな?
同じくらい便利なら100円や200円くらい払うんだけどなぁ。
> ・longの符号は処理系依存なので、変数宣言では符号を明記する。
> 私はそんな処理系聞いたことないです・・・もしかして存在します?
longの符号?聞いたことないですね。
longやshortはsizeが不明なので 使用禁止で
sizeが符号が重要な場面ではint8_t, uint8_t, int16_t, uint16_t...を
sizeが重要じゃなければintを使えって言うのは、今まさにそうですが。
#charも文字列を格納するchar *として使う以外は利用禁止。
これらは、かなり妥当ですよね?
>おまけに'\0'ではなくて、NULLなところが絶句です。
これに関して言うとキャリアが古い人ほど「NULLは数値のゼロだ」という
思い込みが多いように思うのですが、おいらの気のせいでしょうか。
たぶんNULLを記述しているヘッダファイルを読んで
#define NULL 0
と書いているから数値のゼロだと思い込んでいるような。そんな人には
C言語FAQ
http://www.catnet.ne.jp/kouno/c_faq/c_faq.html
の 05. ヌルポインター をお勧めしておきます。
>longの符号は処理系依存なので
これは初耳です。
>ヘンテコ・コーディング規約
そういや最近はJavaでも変な規約をいろいろ聞きます。
おいらが聞いて絶句したのは、
・すべての変数とメソッドに『public static』をつけろ。
・例外を出すメソッドはすべて『throws Exception』をつけろ。
でした。前者はJavaを手続き指向として使うためのノウハウで
おもに元コボル屋さんが採用しているらしいです。
後者は例外の考えが粗雑な人たちなんでしょう。深刻な例外で
あろうが軽微な例外であろうが一律同じExceptionで片付けて
しまえという乱暴さがにおってきて、ちょっと抵抗があります。
私が見たのは、
・関数呼び出し時に返却値を受け取らない場合、明示的に(void)をつける。
printf()から何から全部ついてました。
lintフリーを謳っているところでした。
キャスト地獄になっていたのは言うまでもありません・・・
・文字列の末尾にはNULLを必ず設定すること。
文字列には終端文字が必要というのが理由だったのようですが、
この説明があるってことはC言語を知らないのに、
知っていると入ってきた人間が過去にいたんでしょうかね。
おまけに'\0'ではなくて、NULLなところが絶句です。
お陰で(?)ソースにはみんなNULLと書かれてました。
・charの符号は処理系依存なので、変数宣言では符号を明記する。
コンパイラスイッチで解決して欲しかった。;-<
・longの符号は処理系依存なので、変数宣言では符号を明記する。
私はそんな処理系聞いたことないです・・・もしかして存在します?
もうちょい変な規約が出るとヘンテコ・コーディング規約が作れそうな勢い?:-p
> てのが。たとえば下請けの人が宮坂ソフトの社員だったら
> check_red_zone() という名称ではなく
> MiyasakaKougyou_check_red_zone() という名称にしてください
それだけ長い名前をつけることが許されてるのなら、
それはそれでいいかも。「MiyasakaKougyou001234()」よりは。
> >「1ソースファイル1関数」
>
> 話にはよく聞くけど、これをすると、やたらグローバル変数が増えたり
> ソースファイルを作るたびに申請なんかさせると面倒とばかり、
> 某藤原さんの本みたいな最長不倒関数が量産される結果となります。
ありますね。ていうかこういうプロジェクトでは関数ごとにA4数枚の
「関数仕様書」を要求していたりして、おかげで「関数は普通300行」って
世界ができていくのです。
> 関数名は8文字以内というのも聞いたことがあるような。
私の知っているところでは、関数名は、モジュールをプレフィクスを
付けることになっていたので(これは必要)、8文字ではさすがに収まら
なかったですが。
でも、恐ろしいことに、関数名には命名規則があってもグローバル変数には
なかった… UNIXのCじゃ、こっちの方が怖いことが多いと思うんですが。
> リンカーで取り扱えるサイズがその程度だという
> いったい、いつの時代の話だという根拠だったような。
規格上、いわゆるANSI-Cでも6文字までしか識別してくれませんけど、
気にしてもしょうがない世界ですよねえ…
裏掲示板の話題に対し。
>天下の大企業の規約とは思えんです・・・
いや天下の大企業だから、そういう規約がでるような。
自分が見たのでは、
関数の名称は「企業名+独自名」にする。
てのが。たとえば下請けの人が宮坂ソフトの社員だったら
check_red_zone() という名称ではなく
MiyasakaKougyou_check_red_zone() という名称にしてください
みたいな。
どうも、この規約を作った大企業は同じ会社がずっと下請け仕事を
続けるという今となってはありえない前提で決めたみたいで。
もちろん、こんなナンセンスな規約は誰も守ってなかったですが。
>「1ソースファイル1関数」
話にはよく聞くけど、これをすると、やたらグローバル変数が増えたり
ソースファイルを作るたびに申請なんかさせると面倒とばかり、
某藤原さんの本みたいな最長不倒関数が量産される結果となります。
>変数名は8文字以内
関数名は8文字以内というのも聞いたことがあるような。
リンカーで取り扱えるサイズがその程度だという
いったい、いつの時代の話だという根拠だったような。