struct foo {
char a;
int b;
char c;
};
このとき、並べられた順に a,b,c で割り当てるより、
a,c,b とした方がたいてい詰め物が少ないと思うので。
---
藤井宏憲
それが規格だから。としか答えようありません。
>
> struct foo {
> char a;
> int b;
> char c;
> };
>
> このとき、並べられた順に a,b,c で割り当てるより、
> a,c,b とした方がたいてい詰め物が少ないと思うので。
ならびが保証されていないと、むっちゃ困りますけど、理解できません?
あと、CPUによりますが、複数バイトの同時アクセスが協会を気にしなくても
良いものもありますんで(intel系とか)コンパイラによってはパッキングする
こともあります。
まあ、設計として、上記のようなことをやらないのが基本です。
#って言ってるんだけど、最近64bitのプログラム書いていると、どうしても
#32bitの癖で、たまに8byteバウンダリを忘れちゃう。:-Pま、たいていは数
--
___ わしは、山吹色のかすてーらが大好きでのぅ
[[o o]] ふぉっふぉっふぉ
'J' 森下 お代官様 MaNMOS 英夫@ステラクラフト
PGP Finger = CD EA D5 A8 AD B2 FE 7D 02 74 87 52 7C B7 39 37
struct foo {
int a;
int b;
int c;
char s[1];
};
のように構造体を宣言しておいて、任意の長さの領域を
malloc()してからstruct foo *にキャストして使うなん
てことをむかしのプログラムはよくやってました。つま
りsに任意の長さの領域を割り当てたいからです。
処理系がメンバーの割り当て順序を自由に変更してよい
ことになったら、この手のプログラムは動かなくなる可
能性がありますね。
--
太田純(Junn Ohta) (株)リコー/新横浜事業所
oh...@sdg.mdd.ricoh.co.jp
> > 構造体のメンバの記憶域は並べられた順に割り当てらることとなっていますが、
> > これには何か理由がありますか。
>
> struct foo {
> int a;
> int b;
> int c;
> char s[1];
> };
>
> のように構造体を宣言しておいて、任意の長さの領域を
> malloc()してからstruct foo *にキャストして使うなん
> てことをむかしのプログラムはよくやってました。つま
> りsに任意の長さの領域を割り当てたいからです。
昔どころか…Windows ではいまだに現役ですよ(笑)
とはいっても、可変長の構造体というのはこんな使い方↓をするのが普通ですが。
HOGE *pHoge=malloc(sizeof HOGE);
pHoge->dwSize = sizeof HOGE;
result = GetSomething(pHoge);
if (result == NULL) // 領域不足、dwSize に必要サイズが返される
{
pHoge = realloc(pHoge, pHoge->dwSize);
result = GetSomething(pHoge);
}
構造体 HOGE のサイズが Windows のバージョンアップとともに増えていくので、
古いコンパイラでコンパイルしたコードが新しいバージョンの Windows でも動
くようにするために、こういうトリックを使います。
逆に、SetSomething(pHoge) なんてコードを書くと、先頭の pHoge->dwSize バ
イトだけが認識されて、その先の領域(古いコンパイラでは領域確保されていな
いため、ゴミが入っている)は無視されます。
========================================================================
飯嶋 浩光 / でるもんた・いいじま http://www.ht.sakura.ne.jp/~delmonta/
IIJIMA Hiromitsu, aka Delmonta mailto:delm...@ht.sakura.ne.jp
───【宣伝/ADVERTISEMENT】──────────────────────
fj.os.ms-windows.server2003 または fj.os.ms-windows.server の新設の可否
を問う投票を実施中です。
fj.news.group.comp をご参照のうえ、ふるってご投票ください。
投票期限は 8/25(月)です。
────────────────────────────────────
In article <3F462AE0...@ht.sakura.ne.jp>, IIJIMA Hiromitsu <delm...@ht.sakura.ne.jp> writes
> pHoge = realloc(pHoge, pHoge->dwSize);
> result = GetSomething(pHoge);
で、realloc は絶対に失敗しないと。そういうことなのね。
> 構造体 HOGE のサイズが Windows のバージョンアップとともに増えていくので、
> 古いコンパイラでコンパイルしたコードが新しいバージョンの Windows でも動
> くようにするために、こういうトリックを使います。
むぅ... binary はリコンパイルされないと....
---
Shinji KONO @ Information Engineering, University of the Ryukyus,
PRESTO, Japan Science and Technology Corporation
河野真治 @ 琉球大学工学部情報工学科,
科学技術振興事業団さきがけ研究21(機能と構成)
In article <871xve...@anago2.mas.chi.its.hiroshima-cu.ac.jp>
Fujii Hironori <fu...@chi.its.hiroshima-cu.ac.jp> writes:
> 構造体のメンバの記憶域は並べられた順に割り当てらることとなっていますが、
> これには何か理由がありますか。
はい。ハードウェアのレジスタを叩く時に、書いた通りの順番でな
いと困るからです。C言語はOSのカーネルを記述するために作ら
れた言語なので。
> struct foo {
> char a;
> int b;
> char c;
> };
> このとき、並べられた順に a,b,c で割り当てるより、
> a,c,b とした方がたいてい詰め物が少ないと思うので。
結局、入れ替え可能だった場合は、プログラマに入れ替えてもらえ
ばいいというのが、C言語の思想です。
In article <squ7k56...@stellar.co.jp>
man...@stellar.co.jp (Hideo "Sir MaNMOS" Morishita) writes:
> > このとき、並べられた順に a,b,c で割り当てるより、
> > a,c,b とした方がたいてい詰め物が少ないと思うので。
> ならびが保証されていないと、むっちゃ困りますけど、理解できません?
別に、「むちゃくちゃ」は、困らないんじゃないかなあ。せっかく
よい質問をしてくれているのに。なにもそこまで言わなくても。
手で順序を入れ替えて、ソースを再コンパイルして動くようなプロ
グラムの場合、コンパイラで自動的に入れ替えても結論は同じです。
そんなプログラムを書いている限りは、困ることはありません。
今となっては、標準でコンパイラに構造体の順番の入れ替えを許す
ことにした方が、最適化が効いていいんでしょうね。キャッシュの
関係で、順番を入れ替えたり、意図的に穴をあけたりすると、プロ
グラムが速くなることがあります。この手の最適化は、CPUに依
存するので、本来はプログラマがやる仕事ではありません。コンパ
イラの仕事です。
\\ 新城 靖 (しんじょう やすし) \\
\\ 筑波大学 電子・情報 \\
> はい。ハードウェアのレジスタを叩く時に、書いた通りの順番でな
> いと困るからです。C言語はOSのカーネルを記述するために作ら
> れた言語なので。
精神としてはそういうことでしょうね.どうせポータブルには書けない部分な
んだけど,なるべくstruct定義からメモリ内でのレイアウトが予測できるよう
にして置きたい.すき間のpaddingに関しては,境界に整列しないと動かない
(効率が落ちる)CPUが多いからしょうがないけど,本当の気持ちとしては,そ
の辺もきっちり記述できた方がうれしい(ビットフィールドも).
今の規格では,単に並び順を保証するだけで,すき間は制御できない(コンパ
イルして試してみるしかない)ですけどね.
> 今となっては、標準でコンパイラに構造体の順番の入れ替えを許す
> ことにした方が、最適化が効いていいんでしょうね。キャッシュの
> 関係で、順番を入れ替えたり、意図的に穴をあけたりすると、プロ
> グラムが速くなることがあります。この手の最適化は、CPUに依
> 存するので、本来はプログラマがやる仕事ではありません。コンパ
> イラの仕事です。
飯嶋さんの例にもありましたが,WindowsやX Windowのように,Cで多態もどき
をやりたい時に,先頭の共通部分が同じオフセットに割り付けられないと困り
ませんか?
(C++を使うと,先頭にvtbl_ptrが入っちゃったり…)
前田敦司
In article <m3bruhb...@maedapc.cc.tsukuba.ac.jp>
MAEDA Atusi <ma...@cc.tsukuba.ac.jp> writes:
> 飯嶋さんの例にもありましたが,WindowsやX Windowのように,Cで多態もどき
> をやりたい時に,先頭の共通部分が同じオフセットに割り付けられないと困り
> ませんか?
多態と来ましたか。うむむ。
そういう時には、XDR (SunRPCのmarshaling方式) か何かを使って、
いったんコピーするといいんじゃないでしょうか。
コピーが重たいということなら、フィードアクセス関数のようなも
のを生成するとか。あと、これらのコードに対して
specialization をかけて高速化します。単純なコピーやアクセス
関数は消えてしまうんじゃないかな。
とかね。
In article <m3bruhb...@maedapc.cc.tsukuba.ac.jp>, MAEDA Atusi <ma...@cc.tsukuba.ac.jp> writes
> 精神としてはそういうことでしょうね.どうせポータブルには書けない部分な
> んだけど,なるべくstruct定義からメモリ内でのレイアウトが予測できるよう
> にして置きたい.すき間のpaddingに関しては,境界に整列しないと動かない
> (効率が落ちる)CPUが多いからしょうがないけど,本当の気持ちとしては,そ
> の辺もきっちり記述できた方がうれしい(ビットフィールドも).
このあたりをそろえないと、異なるコンパイラの間の互換性がなく
なります... で実際、互換性がない場合もあるみたい。ひどい...
pragma で指定すると変更できるみたいなものもありますよね。
> 飯嶋さんの例にもありましたが,WindowsやX Windowのように,Cで多態もどき
> をやりたい時に,先頭の共通部分が同じオフセットに割り付けられないと困り
> ませんか?
union で書けばいいんでしょうけど... 疲れますよね。
レジスタは番地をもたないと思っているのですが、
番地のないレジスタに順番がどう影響するのか理解できません。
---
藤井宏憲
このような可変長の構造体は、並べられた順に割り当てると定めた規格を
拡大解釈した規格の乱用だと誰かが言ってたのですが ... 見つからない。
多分、このような可変長の構造体を書くためにこのような
仕様にしているのではない気がする。
---
藤井宏憲
> > レジスタは番地をもたないと思っているのですが、
> > 番地のないレジスタに順番がどう影響するのか理解できません。
>
> メモリマップド I/O とかじゃないですか,
> あと, スッタクフレームいじる時.
CPU によっては、複数のレジスタの内容をまとめてメモリに書き出したりそれを
レジスタに書き戻したりする命令がありますね。たとえば x86 の pusha/pushad。
> > pHoge = realloc(pHoge, pHoge->dwSize);
> > result = GetSomething(pHoge);
>
> で、realloc は絶対に失敗しないと。そういうことなのね。
いえ、本当はきちんとエラー処理します。
今回はサンプルコードなので省いたのですが、その旨書き忘れてました。
> > 構造体 HOGE のサイズが Windows のバージョンアップとともに増えていくので、
> > 古いコンパイラでコンパイルしたコードが新しいバージョンの Windows でも動
> > くようにするために、こういうトリックを使います。
>
> むぅ... binary はリコンパイルされないと....
Windows の世界ではコンパイラ持ってる人のほうが少数派ですから…
バイナリだけで流通するとか、そもそもソース非公開とか、そういうのが昔
(DOS の時代)から当たり前でしたからね。
で、メンテナが失踪してバイナリだけ放置されている例は数知れず…
> 今となっては、標準でコンパイラに構造体の順番の入れ替えを許す
> ことにした方が、最適化が効いていいんでしょうね。キャッシュの
> 関係で、順番を入れ替えたり、意図的に穴をあけたりすると、プロ
> グラムが速くなることがあります。この手の最適化は、CPUに依
> 存するので、本来はプログラマがやる仕事ではありません。コンパ
> イラの仕事です。
御意。でも、標準ライブラリとかシステムコールとかで使う構造体は何らかの形
で「コンパイルオプションに関係なく同じ構造になる」ということが保証されて
いないとまずいような。-march=i386 と -march=pentium4 で並び順が違ったら、
libc とのリンクの際に困ります。
Windows なんかでは #pragma pack(1) の嵐ですけど、UNIX 系の世界でも結局は
#pragma で処理することになるんでしょうね。
========================================================================
飯嶋 浩光 / でるもんた・いいじま http://www.ht.sakura.ne.jp/~delmonta/
IIJIMA Hiromitsu, aka Delmonta mailto:delm...@ht.sakura.ne.jp
───【宣伝/ADVERTISEMENT】──────────────────────
fj.os.ms-windows.server2003 または fj.os.ms-windows.server の新設の可否
を問う投票を実施中です。
fj.news.group.comp をご参照のうえ、ふるってご投票ください。
投票期限は 8/25(月)です。期限が近いのでお急ぎを!
────────────────────────────────────
> In article <871xve...@anago2.mas.chi.its.hiroshima-cu.ac.jp>,
> Fujii Hironori <fu...@chi.its.hiroshima-cu.ac.jp> writes:
> > 構造体のメンバの記憶域は並べられた順に割り当てらることとなっていますが、
> > これには何か理由がありますか。
>
> それが規格だから。としか答えようありません。
なぜ規格をそうしたのかがちょっと不思議に感じるのです。
コンパイラがなぜそうするのかが知りたいのではないです。
At Sat, 23 Aug 2003 14:08:43 +0900,
IIJIMA Hiromitsu wrote:
> > > レジスタは番地をもたないと思っているのですが、
> > > 番地のないレジスタに順番がどう影響するのか理解できません。
> >
> > メモリマップド I/O とかじゃないですか,
> > あと, スッタクフレームいじる時.
>
> CPU によっては、複数のレジスタの内容をまとめてメモリに書き出したりそれを
> レジスタに書き戻したりする命令がありますね。たとえば x86 の pusha/pushad。
char や int のサイズと詰め物のしかたについてが処理系依存なのに、
並びだけ決めても移植性を考えると使えないと思う。
---
藤井宏憲
そもそも、構造体の歴史的起源ってCOBOLのものだと思うんですが、
(それ以前が存在することを御存知の方は御教示ください)
COBOLの構造体は「ファイル入出力の単位」という性格を
明確に主張する仕様になっています。
そもそも、COBOLは「磁気テープ上のデータを読み込んで、加工して、
別の磁気テープに書き出す」処理を行うという発想で設計されていて、
変数は入出力デバイスにリンクしているのが「フツー」であり、
そうではない「作業用一時変数」は継子扱いです。
このような、構造体の「起源的意義」というのは、
C言語などの新しい言語にも、かなりの部分が引継がれていると思います。
流石に「磁気テープ上のファイル」を強烈に意識した部分は消えていますが、
「当該プログラムと、その外の世界との間」でデータを遣り取りする単位
という発想が残された用法は、現在でも主流でしょう。
ディスクファイルはもちろん、
通信に用いるパケットなどの構造も
構造体で記述してまとめて引き渡すのがフツーだし、
各種ライブラリやシステムコールなどとの間で
構造体の構造情報を共有し、それを前提として
構造体の形でデータを授受するというのは、フツーのことですよね。
例えば、
In article <bi586t$i2n$1...@ns.src.ricoh.co.jp> oh...@src.ricoh.co.jp writes:
>struct foo {
> int a;
> int b;
> int c;
> char s[1];
>};
>のように構造体を宣言しておいて、任意の長さの領域を
>malloc()してからstruct foo *にキャストして使うなん
>てことをむかしのプログラムはよくやってました。つま
>りsに任意の長さの領域を割り当てたいからです。
というのにしても、
可変長のデータ云々は、構造体を用いる本来の目的ではありません。
構造体を用いる理由は「a, b, c, s」という「一組のデータ」を
一斉に授受することです。
こういう場合に、構造体に属するデータを
最も簡単かつ確実に弁別する手段は「並び順による照合」です。
例えば名前による弁別では、名前に関する情報を引き渡す仕掛けが必要になり、
状況によっては、そのことが本質的な障害になって
必要な機能が実現できないことも考えられます。
そこまで行かない場合でも、確実にスループットが低下してしまいます。
「並び順による照合」を前提に考えれば、
コンパイラが勝手に順番を変えたら困ることは自明ですよね。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
とりあえず並び順だけでも保証されていたら、
プリプロセッサを駆使して、
複数の処理系で構造体の実質的構造が同一になるように書くこともできます。
それに、同一プログラムを複数の処理系で共有するのが唯一の方法ではありません。
他の処理系が吐き出したファイルを、
処理系の差異を意識したプログラミングによって、
正しく読み出せるようにするなんていう解決方法もある。
#ファイルを読んだ後、整数データ部分の上位バイトと下位バイトを交換して……
#なんて、頻繁に使う処理なんだけどな^_^;
何れにしても、データの順序をプログラマが自由に制御できてこそ、
思い通りにデータが扱えるわけで、
それをコンパイラが好き勝手に変えてしまったら、
できるハズのこともできなくなります。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
> そもそも、構造体の歴史的起源ってCOBOLのものだと思うんですが、
[...]
なるほど、COBOLが起源でしたか。
面白い話をありがとうございました。
またひとつトリビアが増えました。
---
藤井宏憲
> 多態と来ましたか。うむむ。
既に,いっぱい存在しますよね.
キャストを使う
struct sockaddr_in inet_addr;
...
bind(fd, (struct sockaddr *)&inet_addr, ...);
とか.
あるいはunionを使ったXEventとか.
どっちも「structの先頭で同じ宣言の仕方をすれば,同じようにメンバが割り
付けられる」と仮定しないと動かないでしょう.
前田敦司
In article <m365kob...@maedapc.cc.tsukuba.ac.jp>
MAEDA Atusi <ma...@cc.tsukuba.ac.jp> writes:
> キャストを使う
> struct sockaddr_in inet_addr;
> どっちも「structの先頭で同じ宣言の仕方をすれば,同じようにメンバが割り
> 付けられる」と仮定しないと動かないでしょう.
こういう時には、構造体の定義の時に、後ろへの追加を許すように
します。たとえば、こう書きます。
struct sockaddr_base {
sa_family_t sa_family ;
};
struct sockaddr_in : struct sockaddr_base {
in_port_t sin_port ;
struct in_addr sin_addr;
};
#define sin_family sa_family
あと、C#を真似してこう書くとか。
struct sockaddr_in {
sa_family_t sin_family : offset(0) ;
in_port_t sin_port : offset(2) ;
struct in_addr sin_addr : offset(4) ;
};
それから、前の記事に書いたように、XDR を使ってもいいです。ネッ
トワークに流す時には、どうせ何か標準系に変えているので、同じ
ことを、モジュール間でやってもいいでしょう。XEvent も、最後
は、TCP/IP に乗るわけだし。ソースコードがあって、賢いコンパ
イラか部分評価系があれば、XDR で標準系にするオーバヘッドはコ
ンパイル時に全部消えます。
int も、バイト数かビット数を指定できるようにして置けばよかっ
たのにね。int[4] とか、int[8] とか。
いや、そうではないのですよ。
K&R Cのころから、つまり規格なんて存在しなくて「処
理系が言語を規定」していたころからそういうプログラ
ムが広く使われていて、そういうプログラムも破綻しな
いように規格が決められたのではないか、というのが当
方のいいたかったことです。
だから、
> 多分、このような可変長の構造体を書くためにこのような
> 仕様にしているのではない気がする。
これは因果関係が逆ですね。
たいがいのマクロアセンブラの仕様がそうなのと同じ理由では ;)
> char や int のサイズと詰め物のしかたについてが処理系依存なのに、
> 並びだけ決めても移植性を考えると使えないと思う。
「その構造体を使って書いた」データを別の処理系で「その構造体で読む」
ような互換性はないでしょうねもともと。
でも、順番が決まってないと、前述の「最後のメンバーの配列の添字
を多めにつかって可変に」みたいなことができないから困るってことでは?
C++ではできませんが ;)
そういえばいまのCでは
struct {
int len;
char a[];
};
みたいに配列の個数書かないのもOKなんだっけ?
--
ヘ_ヘ ____________________________
ミ・・ ミ vo...@merope.pleiades.or.jp
( ° )~ 日下部陽一
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
oh...@src.ricoh.co.jp (Junn Ohta) writes:
> K&R Cのころから、つまり規格なんて存在しなくて「処
> 理系が言語を規定」していたころから
一応、Reference Manual はありましたが、実態に追い付いていなかっ
たですね。
> そういうプログラ
> ムが広く使われていて、そういうプログラムも破綻しな
> いように規格が決められたのではないか、というのが当
> 方のいいたかったことです。
K&R C では、「先頭部分のメンバーの並び方が同じ構造体は、その部分
が互換である」ことを保証していました。例えば、
struct A { int a; int *p; int i; };
struct B { int a; int *p; double d; };
の場合、a と p は struct A と struct B で同じオフセットを持つこ
とが保証されていました。Unix 7th Edition までは、構造体メンバの
名前空間は、今のように各構造体毎ではなく、構造体メンバ全体で一つ
の空間となっていました。このため、この規定がないと、a や p が多
重定義でエラーになります。
これはパディングに関する規定ですが、メンバーの並び順の規定が前提
となっています。
--
片山@PFU
実は、私は昔Basicで書かれたデータを扱うのに当然Cの構造体つかってアクセ
スするプログラムを書いてましたので、構造体の形が一定しないと「めっちゃ
不便」なのでありました。
#同じコンパイラ同士でデータ扱うならいざ知らず。
> struct sockaddr_in : struct sockaddr_base {
> in_port_t sin_port ;
> struct in_addr sin_addr;
> };
この書き方って、C89 や、もっと遡って K&R 時代にはありましたっけ?
C++ ならこれでいいとわかりますし、C99 で追加されてもおかしくない構文では
ありますが…
> int も、バイト数かビット数を指定できるようにして置けばよかっ
> たのにね。int[4] とか、int[8] とか。
それは、1 バイトが 8 ビットではないプロセッサへの配慮では。
C99 では stdint.h が導入されてますけど、まだ対応していない処理系多し。
> そういえばいまのCでは
> struct {
> int len;
> char a[];
> };
> みたいに配列の個数書かないのもOKなんだっけ?
OKです.もちろん最後のメンバだけ.
struct s1 {
int len;
char a[];
};
と同じ用途で,むかしは個数を書かなきゃいけなかったので,
struct s2 {
int len;
char a[1];
};
と書いたりしたと思いますが,上の2つの書き方でaのオフセットが同じになる
ことが保証されています.(sizeof(struct s1)とoffsetof(struct s1, a)と
offsetof(struct s2, a)は同じになる.)
前田敦司
アセンブリ言語なら完全に一致させられるんでしょうけど,人間が整列まで気
にするのは面倒すぎるし,移植性がなくなっちゃう.
1.が基本的な機能で,CPUの制限から3は厳密には無理になった.その結果2に
も使えなくなった.
ただ,戸田さんも指摘している通り,「コンパイラがどう並べ替えても良い」
と「コンパイラが適宜paddingしてよい」だと,移植性を高めるために必要な
労力が大幅に違います.
たとえば2の用途で,n個のメンバを持つ構造体を異なる計算機で読み書きする
時にはn-1箇所のpaddingを調べれば良いのに対して,並べ替えられてしまうと
お手上げです.どう記述しても希望した並び順にはならないかも知れない.
2の用途はあきらめてXDRなり自分でバイト単位で読み書きするなりするのが,
移植性という観点からは真っ当なんでしょう.同じ処理系で読み書きする一時
ファイルなんかはstructの配列のままread/writeしたいですけどね.効率を考
えると.
3.の用途(多態の例)に関していうと,オブジェクトを勝手にコピーしては動か
ない訳で,言語を大幅に拡張しない限りは,ある程度の規定がないと困ると思
います.
可変部分をunionにして完全にポータブルにすることも可能でしょうけど,
・structのサイズとして,「とりうる最大のサイズ」を取る必要がある.
・「後で拡張する」ことができなくなる.たとえば,sockaddrの定義中に
sockaddr_in, sockaddr_un, sockaddr_x25, ...の定義をあらかじめ全部
含めなければいけなくなる.
ので,用途が限られてしまいます.
y...@is.tsukuba.ac.jp (Yasushi Shinjo) writes:
> > どっちも「structの先頭で同じ宣言の仕方をすれば,同じようにメンバが割り
> > 付けられる」と仮定しないと動かないでしょう.
>
> こういう時には、構造体の定義の時に、後ろへの追加を許すように
> します。たとえば、こう書きます。
> struct sockaddr_in : struct sockaddr_base {
> in_port_t sin_port ;
> struct in_addr sin_addr;
> };
そういうふうにC言語を拡張する訳ですか.
Oberonのextended recordみたいですね.
type
sockaddr_base = RECORD ... END;
sockaddr_in = RECORD (sockaddr_base)
sin_port: in_port_type;
sin_addr: in_addr
END
あるいはCommon Lispの(defstruct ... (:include 親struct) ...)みたい.
効率も良いし,便利でしょうね.
> それから、前の記事に書いたように、XDR を使ってもいいです。ネッ
> トワークに流す時には、どうせ何か標準系に変えているので、同じ
> ことを、モジュール間でやってもいいでしょう。
I/Oに関してはこれで良いと思います.継承(もどき)について他の手段がある
なら,メモリ上の配置もコンパイラ任せで良い.
Javaはそういう考え方ですね.classのメンバの並びはどうでも良い.前方参
照しても関係ない.実際,メモリ上のレイアウトは宣言順でなく並べ替える処
理系が存在します(基本型と,GCが見る必要のある参照型を分けて配置する).
メンバのメモリ上の位置がプログラマに見えることは無いので,これで良いん
ですね.レコードをI/Oする時はmarshaling (serialization)します.配置を
決めたければ,自分でバイト単位で読み書きします.
> XEvent も、最後
> は、TCP/IP に乗るわけだし。ソースコードがあって、賢いコンパ
> イラか部分評価系があれば、XDR で標準系にするオーバヘッドはコ
> ンパイル時に全部消えます。
いや,実際上それはちょっと…
モジュール化ができなくなってしまう.
ライブラリをリンクする際も全部ソースからコンパイルし直しというのは…
結局,特に3の用途を考えると,同じように記述すれば並び順と(規格では保証
されていないけど)配置を同じにしてくれないと動かないプログラムが多数あ
ると思います.
# そうすると,「並び順だけ保証する」という規格は確かに中途半端ですね.
前田敦司
> キャストを使う
> struct sockaddr_in inet_addr;
> ...
> bind(fd, (struct sockaddr *)&inet_addr, ...);
> とか.
>
> あるいはunionを使ったXEventとか.
>
> どっちも「structの先頭で同じ宣言の仕方をすれば,同じようにメンバが割り
> 付けられる」と仮定しないと動かないでしょう.
共用体のなかの構造体だけは特別に保証されるそうです。
構造体の先頭に詰め物がされないことになっているので、
以下のような継承もできそうです。
struct object {
int id;
};
struct rect {
struct object object;
int width, height;
};
struct window {
struct rect rect;
int x, y;
};
struct window w;
((struct object*)&w)->id = WINDOW_ID;
---
藤井宏憲
移植性なんて関係ありません。
まず、目の前の1つの機種の計算機のハードウェア依存部分が
高級言語で書けること。これが必要です。
動かないコードに移植性があっても無意味。
ハードウェアを制御するコードを書くことができて、次に移植性
があればより良いなぁとなるわけで。UNIXだって、コンテキスト
スイッチの部分や割り込みハンドラなどはCPU毎に違うソースファ
イルになってます。
アプリケーションプログラミングと同じ感覚でシステムプログラミング
をとらえてはいけません。本質的に移植性を持たせられないところも
あるのだし、そこをアセンブラではなく高級言語で記述できると
いうのは意味のあること。
それに、
移植性が良いというのは、「移植作業が楽だ」ということで
あって、「ソース無変更で再コンパイルだけで済むこと」では
ありませんよ。
to...@lbm.go.jp wrote:
> そもそも、構造体の歴史的起源ってCOBOLのものだと思うんですが、
> (それ以前が存在することを御存知の方は御教示ください)
Cのstructは、PDP-11のアセンブラの FRAME疑似命令が
起源だと思いますが。
>>> struct foo {
>>> int a;
>>> int b;
>>> int c;
>>> char s[1];
>>> };
>>このような可変長の構造体は、並べられた順に割り当てると定めた規格を
>>拡大解釈した規格の乱用だと誰かが言ってたのですが ... 見つからない。
この技法をDennis Ritchieは「Cの実装への根拠のない馴れ馴れしさ」と
呼んだそうです。(それのことで?)
http://www.catnet.ne.jp/kouno/c_faq/c2.html#6
--
matu.
In article <bic3a2$nsg$2...@newsserv.ics.es.osaka-u.ac.jp> sai...@ist.osaka-u.ac.jp writes:
>> そもそも、構造体の歴史的起源ってCOBOLのものだと思うんですが、
>> (それ以前が存在することを御存知の方は御教示ください)
>Cのstructは、PDP-11のアセンブラの FRAME疑似命令が
>起源だと思いますが。
直接の起源をターゲット機のアセンブラに求めますか……
いくらC言語が「高級アセンブラ」だからって、
それだけが起源だと断定するのはどうでしょうね。
また、アセンブラにそういう疑似命令を準備したというのが、
過去の高級言語からの発想という可能性もありそうですし……
私の断片的な知識を、ざっとまとめてみました。
(1)algolには構造体に相当する概念は無い。
FORTRANのCOMMONブロックは、
バイナリレベルでは外部構造体(C言語のextern struct)と
同等に扱われることが多いと思われるが、発想は違いそう。
即ち、1950年代に開発された高級言語の「御三家」で、
構造体に相当する概念があるのはCOBOLだけである。
(2)しかし、COBOLでは「構造体(structure)」という用語は用いていない。
この用語が規格レベルで出てきたのは、PL/I(1964年)ではないかと
思われるが、確かな証拠は今のところ得られていない。
(3)Pascal(1968年)では構造体に相当するものを「record型」と呼んでいる。
この呼称は、COBOLの構造体がファイル入出力における「record」の概念と
密接に結びついているところから来ているのではないかとの推測が成り立つが、
あくまで推測に過ぎない。
ちなみに、C言語は1972年に開発されたことになっており、
前身を遡るとB言語(1970年)←BCPL(1967年)←CPL(1963年)となるようです。
(CPLの前身はalgolまで行き着いてしまう)
COBOLにおける構造体の概念がファイル入出力と密接に結びついている
ということは、前電でも
In article <bi73b2$u5m$1...@bluegill.lbm.go.jp> I write:
>COBOLの構造体は「ファイル入出力の単位」という性格を
>明確に主張する仕様になっています。
>そもそも、COBOLは「磁気テープ上のデータを読み込んで、加工して、
>別の磁気テープに書き出す」処理を行うという発想で設計されていて、
>変数は入出力デバイスにリンクしているのが「フツー」であり、
>そうではない「作業用一時変数」は継子扱いです。
と説明した通りですが、もう少し詳しく説明してみます。
COBOL以外のほとんどの高級言語のファイル入出力では、
例えば出力の場合には、プログラム中で記述された変数領域のデータを、
プログラムでは直接見えない「入出力バッファ」領域に複写して
(書式つき出力の場合には、書式に従った変換結果をバッファ領域に書込んで)、
その(直接見えない)データをデバイスに引き渡すという手順だと思います。
ところが、COBOLでは「入出力バッファ」の中に、
当該入出力デバイス専用の(プログラムから見える)変数を確保する
という発想になっています。
(実際には、デバイスとの間にワンクッション置く実装が多いと思われるが、
言語の習得に際しては、そのことを意識しない方が解りやすい)
書式つき出力にしても「出力バッファ内の変数」への
代入に際して書式に従った変換が行われるという発想です。
(つまりバッファ内の各変数の属性の1つとして“書式”がある)
そうすると、入出力単位である「レコード」は、
「内容は多種多様だが、組(前田さんのいう“tuple”)として
まとまっているデータ群」になりますから、
その中身は自ずから構造体の性格を有することになります。
そのため、COBOLでは他の構造体の要素ではない「一番上のレベルの」構造体と、
入出力単位である「レコード」が同義語になるんですね。
なお、「一番上のレベル」に限らない、中間レベルも含めた構造体のことは、
COBOLでは集団項目(group item)と呼んでいます。
FORTRANだと、バイナリ入出力にも「入出力並び」があって、
レコードは個々の入出力文の並びで「1回ごとに定義される」
「偶々その場に居合せたというだけの集団」という感覚ですが、
COBOLではそれが「恒常的な社会集団(??)」であることを要求しているわけです。
この点、PL/Iでは書式なしのREAD/WRITE(RECORD入出力)では
「並び」ではなく「1個の変数(=構造体を想定)」を引数とするのに対して、
書式つきのGET/PUT(STREAM入出力)では引数は「並び」と使い分けられています。
C言語でもfread/fwriteで入出力されるデータは「1個の引数」なのに対して、
fscanf/fprintfでは「不定数の引数」になるというのは似たような発想ですね。
ただ、PL/IにしてもC言語にしても、
変数が言語仕様上は「当該デバイス専用」ではないというところが、
COBOLと異なります。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
C言語の「構造体」の考え方の元は、PL/1 だと思います。正確に
は、PL/Iという、PL/1 のサブセットで、Multics の記述に使われ
たもの。
C言語の /**/ のコメントも、PL/1 と同じです。
In article <bieihv$p5r$1...@bluegill.lbm.go.jp>
to...@lbm.go.jp writes:
> (2)しかし、COBOLでは「構造体(structure)」という用語は用いていない。
> この用語が規格レベルで出てきたのは、PL/I(1964年)ではないかと
> 思われるが、確かな証拠は今のところ得られていない。
PL/1 は、Fortran と Cobol を会わせて1つで記述しようというこ
とで作られた言語なので、C の構造体の元が Cobol というのは、
ある意味では正解なんでしょう。
Cを先に勉強してから PL/1 を見た時には、PL/1 は、かっこ悪い
感じがしました。構造体の定義で、ネストのレベルを現すのに数字
を書かないといけなかったと思います。
情報ありがとうございます。
ところで、Subject:には「PL/M」とあるのですが、
本文の方が書き誤りと考えて良いでしょうか?
(PL/IのサブセットのPL/Mというのは聞き覚えがあるので……)
>Cを先に勉強してから PL/1 を見た時には、PL/1 は、かっこ悪い
>感じがしました。構造体の定義で、ネストのレベルを現すのに数字
>を書かないといけなかったと思います。
この仕様は、COBOLそのまんまです。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
to...@lbm.go.jp wrote:
>>Cのstructは、PDP-11のアセンブラの FRAME疑似命令が
>>起源だと思いますが。
> 直接の起源をターゲット機のアセンブラに求めますか……
> いくらC言語が「高級アセンブラ」だからって、
> それだけが起源だと断定するのはどうでしょうね。
> また、アセンブラにそういう疑似命令を準備したというのが、
> 過去の高級言語からの発想という可能性もありそうですし……
構造体(の概念)の起源がFRAMEだとはいってません。あくまでもCの
structの話です。
他の言語に構造体があったからCにもstruct機能をつけようと
発想したのではなく、アセンブラでFRAME機能を使っていたのを
容易に移行できるようにstructを導入したのではないでしょう
かね。
<to...@lbm.go.jp> wrote in message news:bif0l6$u7v$1...@bluegill.lbm.go.jp...
> In article <YAS.03Au...@kirk.is.tsukuba.ac.jp> y...@is.tsukuba.ac.jp
writes:
> >C言語の「構造体」の考え方の元は、PL/1 だと思います。正確に
> >は、PL/Iという、PL/1 のサブセットで、Multics の記述に使われ
> >たもの。
>
> ところで、Subject:には「PL/M」とあるのですが、
> 本文の方が書き誤りと考えて良いでしょうか?
> (PL/IのサブセットのPL/Mというのは聞き覚えがあるので……)
PL/1とPL/Iは同じではないのでしょうか。ちょっと探してみましたが,PL/Iの上位の
言語を見つけれませんでした。PL/IのサブセットでEPLというのは,見つかりました
が。
ところで,「構造体」の考え方の元がPL/Iというのは,その通りかも知れませんが。
ところで
The Development of the C Language
Dennis M. Ritchie
Bell Labs/Lucent Technologies
Murray Hill, NJ 07974 USA
(http://www.cs.bell-labs.com/who/dmr/chist.html)
に以下のような記述がありました。
中略
Embryonic C
中略
These semantics represented an easy transition from B, and I experimented
with them for some months. Problems became evident when I tried to extend
the type notation, especially to add structured (record) types. Structures,
it seemed, should map in an intuitive way onto memory in the machine, but in
a structure containing an array, there was no good place to stash the
pointer containing the base of the array, nor any convenient way to arrange
that it be initialized.
リッチーは,構造体の実装にかなり苦労したようですが,その並びについては直感的
にメモリに割り付けるべきと考えていたようです。(直感的とは,並び順に素直に割
り付けるという意味でしょうか。)
中略
また,Cにおける型のデザイン(構造体を含め)については,
The scheme of type composition adopted by C owes considerable debt to Algol
68, although it did not, perhaps, emerge in a form that Algol's adherents
would approve of. The central notion I captured from Algol was a type
structure based on atomic types (including structures), composed into
arrays, pointers (references), and functions (procedures). Algol 68's
concept of unions and casts also had an influence that appeared later.
Algol 68に負うところが多いと言っているようです。
--
******************************
keizi kounoike
******************************
> C言語の /**/ のコメントも、PL/1 と同じです。
…はっ、そういえば。
> PL/1 は、Fortran と Cobol を会わせて1つで記述しようというこ
> とで作られた言語なので、C の構造体の元が Cobol というのは、
> ある意味では正解なんでしょう。
じゃ、共用体はREDEFINE?
--
--
Akihito Nakamura( Chun )
> PL/1とPL/Iは同じではないのでしょうか。ちょっと探してみましたが,PL/Iの上位の
> 言語を見つけれませんでした。PL/IのサブセットでEPLというのは,見つかりました
> が。
http://www.net.intap.or.jp/oiia/cont1/p0302.html{0recid=10112.html
によると
PL/I(初期にはPL/1と表記されていたが、現在はPL/Iが正しい)
そうです。
In article <bihokq$o3q$1...@nn-tk102.ocn.ad.jp>, "Akihito Nakamura" <ch...@bekkoame.ne.jp> writes
> PL/I(初期にはPL/1と表記されていたが、現在はPL/Iが正しい)
> そうです。
IBM は PL/2 を作ろうとはしなかったんですかねぇ。??/2 という
商標を取りまくった時期があるらしいんですが...
---
Shinji KONO @ Information Engineering, University of the Ryukyus,
PRESTO, Japan Science and Technology Corporation
河野真治 @ 琉球大学工学部情報工学科,
科学技術振興事業団さきがけ研究21(機能と構成)
In article <YAS.03Au...@kirk.is.tsukuba.ac.jp> y...@is.tsukuba.ac.jp wrote on Tue, 26 Aug 2003 06:00:42 GMT:
>PL/1 は、Fortran と Cobol を会わせて1つで記述しようというこ
>とで作られた言語なので、C の構造体の元が Cobol というのは、
>ある意味では正解なんでしょう。
PL/IはFORTRANとCOBOLとALGOLを一つにしたとどこかで聞いたような。
出所はよく憶えていない。
PL/IのコンパイラでFORTRANのソース+αがコンパイルできれば、
結構売れただろうに。
-----------------------------------------------------------------
電力中央研究所 電力システム部 竹中 清
- kiyos - kiyos - kiyos - kiyos - kiyos - kiyos - kiyos - kiyos -
take...@criepi.denken.or.jp
In article <bif0l6$u7v$1...@bluegill.lbm.go.jp>
to...@lbm.go.jp writes:
> ところで、Subject:には「PL/M」とあるのですが、
> 本文の方が書き誤りと考えて良いでしょうか?
すみません。間違えました。Multics だから M かなあと、
Subject: を書く時に思っていたのですが、本文書く時には、PL/1
でいいかと思って。
http://www.multicians.org/pl1-raf.html
------------------------------------------------------------
The language
The Multics PL/1 language is the language defined by the IBM
"PL/1 Language Specifications" dated March 1968. At the time
this paper was written most language features were
implemented by the compiler but the run time library did not
include support for input and output, as well as several
lesser features. Since the multi-tasking primitives provided
by the Multics operating system were not well suited to PL/1
tasking, PL/1 tasking was not implemented. Inter-process
communication (Multics tasking) may be performed through
calls to operating system facilities.
------------------------------------------------------------
> >Cを先に勉強してから PL/1 を見た時には、PL/1 は、かっこ悪い
> >感じがしました。構造体の定義で、ネストのレベルを現すのに数字
> >を書かないといけなかったと思います。
> この仕様は、COBOLそのまんまです。
そうでしたか。Cobol は、書いたことがないので。
http://www.users.bigpond.com/robin_v/c2pli.htm より構造体の
宣言の仕方の対比があったので抜き出しておきます。
C言語:
struct S {
int p;
float q;
};
PL/1:
DECLARE 1 S,
3 p FIXED BINARY,
3 q FLOAT DECIMAL;
C言語(ビットフィールド)
struct T {
unsigned int u : 1;
unsigned int v : 2;
unsigned int w : 0;
};
Note that a zero field is filled out to a byte boundary as shown.
PL/1:
DECLARE 1 T,
3 u BIT (1) UNALIGNED,
3 v BIT (2) UNALIGNED,
3 w BIT (5) UNALIGNED;
過去の話もいいんですが、未来の話ももっとしたいですね。
現在のCの規格が、未来永劫変るわけでもないし。
In article <m3wud3a...@maedapc.cc.tsukuba.ac.jp>
MAEDA Atusi <ma...@cc.tsukuba.ac.jp> writes:
> そうか.結局structの宣言は,
> 1.プログラミングで使う組(tuple)データをある程度抽象的に記述したもの
> 2.ファイルI/Oや通信の際の入出力レコードを具体的に記述したもの
> 3.メモリ上のレイアウトを具体的に記述したもの
> の3つを,当初は兼ねていたけど,だんだん苦しくなっているんですね.
あと何年くらい、持ちますかね。
1だけでいいなら、Cを使うなという話はあります。構造体のせい
ではないと思いますが、CよりJavaの方がずっと高い生産性を
あげる人がいます。両方できる人はそんなに生産性は変らないのか
もしれないけれど、Cだといつまでたってもできないのに、Java
ならプログラムが完成するという例はあります。
で、Javaで、2., 3. を書こうとすると、終ってしまうんですよね。
> Javaはそういう考え方ですね.classのメンバの並びはどうでも良い.前方参
> 照しても関係ない.実際,メモリ上のレイアウトは宣言順でなく並べ替える処
> 理系が存在します(基本型と,GCが見る必要のある参照型を分けて配置する).
> メンバのメモリ上の位置がプログラマに見えることは無いので,これで良いん
> ですね.レコードをI/Oする時はmarshaling (serialization)します.配置を
> 決めたければ,自分でバイト単位で読み書きします.
具体的に、Java から SunRPC (XDR) で提供されているサービスを
使いたいと思った時に、実際どの程度の難しさでできるのでしょうか。
> 可変部分をunionにして完全にポータブルにすることも可能でしょうけど,
> ・structのサイズとして,「とりうる最大のサイズ」を取る必要がある.
> ・「後で拡張する」ことができなくなる.たとえば,sockaddrの定義中に
> sockaddr_in, sockaddr_un, sockaddr_x25, ...の定義をあらかじめ全部
> 含めなければいけなくなる.
> ので,用途が限られてしまいます.
Linux のカーネルで、VFS 層のinode の定義がこんな感じの巨大な
union になっていたと思いました。
> いや,実際上それはちょっと…
> モジュール化ができなくなってしまう.
> ライブラリをリンクする際も全部ソースからコンパイルし直しというのは…
ソースがあれば、速いけれど、ソースがなくても普通に XDR をす
ればいいので、RPC すると思えば、今の CPU で問題ない速度が出
ると思います。
> リッチーは,構造体の実装にかなり苦労したようですが,その並びについては直感的
> にメモリに割り付けるべきと考えていたようです。(直感的とは,並び順に素直に割
> り付けるという意味でしょうか。)
このすぐ下のディレクトリエントリをファイルから読む例で,
I wanted the structure not merely to characterize an abstract object
but also to describe a collection of bits that might be read from a directory.
というところが興味深いですね.やっぱり,単なる抽象的なタプルの表現でな
く,メモリ上,ファイル上のビットパターンをそのまま記述できるものにした
かったんですね.
前田敦司
> 具体的に、Java から SunRPC (XDR) で提供されているサービスを
> 使いたいと思った時に、実際どの程度の難しさでできるのでしょうか。
通信データの形式をXDRに合わせなければいけない場合ですね?
Pure Javaだと,rpcgenを使わないでCで書くより面倒でしょう.
ByteArrayOutputStream data = new ByteArrayOutputStream();
dOut = new DataOutputStream(data);
...
dOut.writeInt(RPC_CALL);
dOut.writeInt(RPC_VERSION);
dOut.writeInt(RPC_PROG_NUM_NFS);
...
byte[] dataBytes = data.getBytes();
DatagramPacket packet =
new DatagramPacket(dataBytes, 0, dataBytes.length, inet_address, port);
とかやるんでしょうね(まあ,もうちょっと抽象化するでしょうけど).
データ形式がどうでも良くて,RMIを使って良いなら,SunRPCと同じくらい楽
です.
> > いや,実際上それはちょっと…
> > モジュール化ができなくなってしまう.
> > ライブラリをリンクする際も全部ソースからコンパイルし直しというのは…
>
> ソースがあれば、速いけれど、ソースがなくても普通に XDR をす
> ればいいので、RPC すると思えば、今の CPU で問題ない速度が出
> ると思います。
XEventとかは「オブジェクト指向の継承もどき」なんですけど,モジュール間
でも「通信」とみなしてXDR形式へいったん変換する(部分評価できれば変換は
省略する)とすると,
・キャストのたびにXDR経由で変換するのは,さすがに遅いんでは.まあ,
XEventくらいだと大丈夫かも知れんですけど.一般に「継承」を「XDRへの
変換」で実装しちゃうのは遅そう.
・複数のポインタから共有されている時,別のアドレスのXDR形式データにコ
ピーしちゃうとidentityが保てなくなるので,動かなくなるのでは.(メソッ
ド呼び出し/復帰のタイミングでしかやらないんなら,ライトバックすれば
良いのかな.)
継承もどきをやりたいとき,現状では,藤井さんから
<87wud2...@anago2.mas.chi.its.hiroshima-cu.ac.jp> でフォローがあっ
たように,親structを先頭に書くようにするのが良さそうですね.親の型へ変
換する際にはキャストさえ不要だし.
前田敦司
Yasushi Shinjo wrote:
> 新城@筑波大学情報です。こんにちは。
>>そうか.結局structの宣言は,
>>1.プログラミングで使う組(tuple)データをある程度抽象的に記述したもの
>>2.ファイルI/Oや通信の際の入出力レコードを具体的に記述したもの
>>3.メモリ上のレイアウトを具体的に記述したもの
>>の3つを,当初は兼ねていたけど,だんだん苦しくなっているんですね.
> 1だけでいいなら、Cを使うなという話はあります。
> Cだといつまでたってもできないのに、Java
> ならプログラムが完成するという例はあります。
> で、Javaで、2., 3. を書こうとすると、終ってしまうんですよね。
ANSIC以降の流れは、Cを改良したつもりで引導を渡している
のではないかという気がしています。高級アセンブラだから
Cは意味があるのに。きれいに定義した高級言語がつかいたけ
れば、Cをつかわずにもっと他の優れた言語を使えばいいわけで。
トライグラフみたいな政治的妥協の産物がはいって来ちゃうし。
COBOLやFORTRANはどうなんでしょう?これらも、構造化プログラミング
とか文字列処理とを取り入れようとして改訂が重ねられて
来ていると思いますが。本当に最新規格が広く使われているんでしょ
うか? すみません。FORTRANは77で知識が止まってます。
In article <bihokq$o3q$1...@nn-tk102.ocn.ad.jp> ch...@bekkoame.ne.jp writes:
>> PL/1とPL/Iは同じではないのでしょうか。ちょっと探してみましたが,PL/Iの上位の
>> 言語を見つけれませんでした。PL/IのサブセットでEPLというのは,見つかりました
>> が。
>http://www.net.intap.or.jp/oiia/cont1/p0302.html{0recid=10112.html
>によると
> PL/I(初期にはPL/1と表記されていたが、現在はPL/Iが正しい)
>そうです。
でも「I」を「one」と読むんですよね。
「IBMのI」だという話もあるんですが、
読み方からすると「ローマ数字の壱」なのかなあ?
「IBM as No.1」ってこと?
In article <bihqr1$1ga$1...@dnknews.denken.or.jp> take...@criepi.denken.or.jp writes:
> >PL/1 は、Fortran と Cobol を会わせて1つで記述しようというこ
> >とで作られた言語なので、C の構造体の元が Cobol というのは、
> >ある意味では正解なんでしょう。
>PL/IはFORTRANとCOBOLとALGOLを一つにしたとどこかで聞いたような。
>出所はよく憶えていない。
文を行単位ではなく「;」で区切るという発想は、間違い無くalgol起源ですね。
ただ、algolの「;」が分離記号(delimiter)なのを、
PL/Iでは終端記号(terminator)に変えちゃった。
ついでに、algolでは「文という単位から超越した記号」だった
「begin」や「end」などを、FORTRAN的な発想の「制御文」に変えちゃいました。
「BEGIN;」「END;」と、「;」を付けて、それで1つの「文」なんですね。
これは、行という単位に文法上の意味があるFORTRANやCOBOLとの
親和性を求めた結果なんだと思います。
#PL/Iの「BEGIN;」はインラインの「手続き」とも言えるような強い区切りなので、
#algolの「begin」は「DO;」に相当すると考える方が正確かもしれません。
「;」が終端記号であるという特徴はC言語にも受け継がれていますね。
実際、Pascalを勉強しているときにイライラしたことなんですが、
「プログラムの入れ子構造を段下げで表現」したりするなど、
2次元的な広がりの中でプログラムを理解して読み書きしようとすると、
「;」がalgol式に分離記号であるという定義とは相容れないのです。
分離記号の「;」は、あくまでプログラムを1次元的に理解することを
前提にした流儀だと言え、2次元的にプログラムを書く現実には
そぐわないものだと思っています。
この点、C言語はPL/Iの特徴を良い具合に受け継いだと言えると思います。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
In article <bii3h8$qh2$1...@newsserv.ics.es.osaka-u.ac.jp>, SAITOH akinori <sai...@ist.osaka-u.ac.jp> writes
> ANSIC以降の流れは、Cを改良したつもりで引導を渡している
> のではないかという気がしています。高級アセンブラだから
> Cは意味があるのに。きれいに定義した高級言語がつかいたけ
> れば、Cをつかわずにもっと他の優れた言語を使えばいいわけで。
そう考えている人は何人かいるみたいで、C-- とかありますね。僕
も一つ言語を作ったな。
> トライグラフみたいな政治的妥協の産物がはいって来ちゃうし。
あれが生きていると思っている人はいないんじゃないかな。
> うか? すみません。FORTRANは77で知識が止まってます。
FORTRAN は、毎年毎年、別物.... しかし、昔のプログラムは動く
と言う...
> MAEDA Atusi wrote:
> > どっちも「structの先頭で同じ宣言の仕方をすれば,同じようにメンバが割り
> > 付けられる」と仮定しないと動かないでしょう.
>
> 共用体のなかの構造体だけは特別に保証されるそうです。
>
> 構造体の先頭に詰め物がされないことになっているので、
> 以下のような継承もできそうです。
ほんとだ.ちゃんと規格にありますね(ISO/IEC 9899:1999の,それぞれ
6.5.2.3 #5と.6.7.2.1 #13).
えーと,
共用体のメンバーの複数の構造体が「共通の先頭部分」を持っているとき,
共用体の完全な定義が可視である場所ならば,(今どの構造体が入っている
か不明でも)先頭部分に触って良い(6.5.2.3 #5;大意)
どの構造体へのポインタも同じ形式で,alignment requirementsも同じであ
る(6.2.5 #26)
共用体へのポインタは(適切に変換すれば)各メンバを指す.逆もまた真.
(6.7.2.1 #14)
であるわけですから,例えば共通の先頭部分を持つ構造体
struct s1 { int common; ... };
struct s2 { int common; ... };
があるとき,てきとーな共用体
union u {
struct s1 s1;
struct s2 s2;
};
が「可視である場所ならば」,
struct s1 *p1;
から
struct s2 *p2 = (struct s2 *)((union u *)p1);
と変換して s2->common を読み書きするのはかまわないわけですね.
で,上のunion uの定義なしで
struct s2 *p2 = (struct s2 *)p1;
とやってs2->commonを読み書きするのは規格ではなんと「ダメ」なようです
(6.5.2.3 EXAMPLE 3).
しかし,union uの定義のあるなしでstruct s1やs2のメンバのオフセットが変
わるなんてあり得ないと思うけどなあ… union uの定義が見えるファイルでも,
見えないファイルでも,同じstruct s1が使えるんだから.
実質(union u *)なしでも同じでしょう.ようするに,sockaddr_inやXEventで
やってることはOKと.
# いや,誰も「ダメ」と言った人はいないと思うんですが...
前田敦司
In article <bii43j$2m4$1...@bluegill.lbm.go.jp>, to...@lbm.go.jp writes
> PL/MというのはCP/Mの記述言語で、Multicsとは関係無いようです。
> http://contest.thinkquest.gr.jp/tqj1999/20204/bbs/f/freetalk/10/
PL/M はインテルのマイクロプロセッサ用の言語です。
CP/M 80がPL/Mでかかれていたってのは僕は信じられないです。
CP/M は、たぶん、アセンブラで書かれていたんだろうと思う。
CP/M 86 とか 68k は違うかも知れませんが。
一回だけ使ったことあるんだけど、むごい言語だと思った。
再帰がだめとかつまんない制約があったような気がするし。
> 読み方からすると「ローマ数字の壱」なのかなあ?
> 「IBM as No.1」ってこと?
Programming Language 1 ですよね。1 つですませたいっていう
意味だったかも。PL だけでは少ないと思ったんだろうな。
> ただ、algolの「;」が分離記号(delimiter)なのを、
> PL/Iでは終端記号(terminator)に変えちゃった。
declare を de とか書くのが普通になった時点で終ったんじゃない
かと思います。
> 「;」が終端記号であるという特徴はC言語にも受け継がれていますね。
> 実際、Pascalを勉強しているときにイライラしたことなんですが、
> 「プログラムの入れ子構造を段下げで表現」したりするなど、
> 2次元的な広がりの中でプログラムを理解して読み書きしようとすると、
> 「;」がalgol式に分離記号であるという定義とは相容れないのです。
C の実用的ですよね。
ko...@ie.u-ryukyu.ac.jp (Shinji KONO) writes:
> In article <bii43j$2m4$1...@bluegill.lbm.go.jp>, to...@lbm.go.jp writes
>> PL/MというのはCP/Mの記述言語で、Multicsとは関係無いようです。
>> http://contest.thinkquest.gr.jp/tqj1999/20204/bbs/f/freetalk/10/
>
> PL/M はインテルのマイクロプロセッサ用の言語です。
>
> CP/M 80がPL/Mでかかれていたってのは僕は信じられないです。
> CP/M は、たぶん、アセンブラで書かれていたんだろうと思う。
CP/Mの本体であるBDOSは読んだ限り明らかにアセンブラで書かれたコードです。
コマンドプロセッサのCCPもアセンブラ。
BIOSのサンプルもアセンブラ提供。
トランジェントコマンド(外部コマンド)のいくつかがPL/Mで書かれていたようです。
SUBMITともうひとつ何か(STATだったか)を読みましたが、レジスタが特徴的な
使われ方をしており、何らかのコンパイラ言語(おそらくPL/M)で書かれていることが
読み取れます。
XSUBは外部コマンドですが、常駐するためかアセンブラで書かれてました。
PL/Mとは別に、CP/M用のPL/Iコンパイラはありましたよ。レベルFだかGだかの
サブセットということでしたが。
--
oo
In article <u7k4zm...@anet.ne.jp>, OOTANI TAKASHI <tks...@anet.ne.jp> writes
> CP/Mの本体であるBDOSは読んだ限り明らかにアセンブラで書かれたコードです。
> コマンドプロセッサのCCPもアセンブラ。
> BIOSのサンプルもアセンブラ提供。
そうだよね。記述言語ってのは、きっとCP/M上で使用できる言語っ
ていう意味なんだろうな。
> SUBMITともうひとつ何か(STATだったか)を読みましたが、レジスタが特徴的な
> 使われ方をしており、何らかのコンパイラ言語(おそらくPL/M)で書かれていることが
> 読み取れます。
SUBMITはそうかも知れない。
> XSUBは外部コマンドですが、常駐するためかアセンブラで書かれてました。
(懐かし~ こいつが何をするか知っている人は、どれだけいるんだろうか?)
> PL/Mとは別に、CP/M用のPL/Iコンパイラはありましたよ。レベルFだかGだかの
> サブセットということでしたが。
僕が最初に触った C は、CP/M 80 上の White Smith C です。
なんと、printf がないという!? Cですな。でも、今から
考えてみると、White Smith C の方がすぐれていたと思う。
次が、Flex 09 上の Micro C, Introl C それから、CP/M 86 上の
Optimizing C です。次に、4.1BSD の C だな。VAX の出力コードは
ほとんど読まなかったな。今から考えるともったいなかった。
バックスラッシュが円記号に化けちゃうような環境のひとは
ほんとうは使わなきゃいけないのでは? ;)
C言語って、プログラムの構造を視覚的に表現することを徹底したのが、
他のalgol系言語に比較しての顕著な長所だと思ってるんですが、
(例えば、「begin」「end」を廃して「{ }」にしたとか)
トライグラフって、この特長を見事に殺しちゃってるんですよね。
FACOM(富士通)のEBCDIC機で使われていた
(EBCDIC機ではわりと一般的だったらしい)
Pascal用の代替表現
[ ] → (. .) (配列添字および集合型データ)
{ } → (* *) (注釈)
の方が、視認性の意味で圧倒的に優れていると思う。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
In article <bii43j$2m4$1...@bluegill.lbm.go.jp> I write:
>>PL/IはFORTRANとCOBOLとALGOLを一つにしたとどこかで聞いたような。
>>出所はよく憶えていない。
>文を行単位ではなく「;」で区切るという発想は、間違い無くalgol起源ですね。
>ただ、algolの「;」が分離記号(delimiter)なのを、
>PL/Iでは終端記号(terminator)に変えちゃった。
>「;」が終端記号であるという特徴はC言語にも受け継がれていますね。
「分離記号」を「delimiter」と訳しましたが、
「separator」の方が良さそうですね。
Pascalの開発者であるWirthがJensenと1974年に共著で出した教科書
(原田賢一訳:培風館1981)では、
「;」は「statement separator」であるとして、
「PL/Iのようなstatement terminatorではない」とまで念押ししてあります。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
to...@lbm.go.jpさんは書きました。
> とりあえず、
> http://www.lbm.go.jp/toda/comp/struct.html
> のような形にまとめてみました。
面白いですがFRAME疑似命令が起源というのはちょっと抵抗あるなあ。
ちなみに他のアセンブラでもメモリは割り当てずにオフセット振るだけ
の疑似命令はありましたよ。360系とかにも。どっちかというと、当時
アセンブリ言語コードで普通に使われていた「インデクス+オフセット」
みたいなアドレシングにそのまま対応づけられるような言語メカニズム
としてとか…
そもそも言語メカニズムというならCの祖先BCPLや親戚BLISSを調べる
必要はあるんじゃないでしょうか。
といいつつ調べていない私。 久野
In article <binp21$1...@utogw.gssm.otsuka.tsukuba.ac.jp> ku...@gssm.otsuka.tsukuba.ac.jp writes:
>> とりあえず、
>> http://www.lbm.go.jp/toda/comp/struct.html
>> のような形にまとめてみました。
> 面白いですがFRAME疑似命令が起源というのはちょっと抵抗あるなあ。
>ちなみに他のアセンブラでもメモリは割り当てずにオフセット振るだけ
>の疑似命令はありましたよ。360系とかにも。
なるほど。
とりあえず、断定を避ける表現に改めてみました。
他にも、自分で読み直してみて気になった部分をざっといじってあります。
> そもそも言語メカニズムというならCの祖先BCPLや親戚BLISSを調べる
>必要はあるんじゃないでしょうか。
ですよね。あと、algol 68も見ておきたいんだけど、
教科書探しから始めねばならない状況です。
ま、そのうち何とかして、きちんと勉強する機会を作って、
それに基づいて自分の責任で改訂することを目指しますが、
既に御存知の方から御指摘をいただければ、
とりあえず当面の改訂はできるので、よろしくお願いします。
#印刷物と違って、際限無く改訂できるし^_^;
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
Pascalのところに、「Algol 60はその妹」とあるんですが、
「Algol 68は」の間違いじゃなかろうか。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
「全く字下げが無くてもプログラムとしては等価です」とあるのですが、COBOLもそうでしたっけ?
確か、字下げが正しくないとコンパイル時にエラーが返ってきたような覚えが…。
A領域とB領域に制限がありますが、
一般的な字下げはチェック対象ではありません。
--
かしわぎともみ kash...@cup.com
そういった意味では、IBMメインフレームのPL/I(現用のPL/Iってメインフレーム
だけでしょうね)では、プログラムは2カラム目から72カラム目の間に書きます。
1カラム目は無視されます。(コンパイルオプションで変更できますが)
何故標準で1カラム目を無視するのか理由はわかりませんが、コメントの開始記号と
JCLのオンヒアドキュメントの終端記号がどちらも /* なのが関係しているのかも。
unix風に書くとこんな感じです:
pli <<'/*'
sample:proc options(main);
/* nanchara kanchara */
end sample;
/*
--
oo
to...@lbm.go.jp writes:
> In article <binuft$49p$1...@bluegill.lbm.go.jp> to...@lbm.go.jp writes:
>>> そもそも言語メカニズムというならCの祖先BCPLや親戚BLISSを調べる
>>>必要はあるんじゃないでしょうか。
>>ですよね。あと、algol 68も見ておきたいんだけど、
>>教科書探しから始めねばならない状況です。
> ということで、とりあえずWebで少しは判らないかと
> いろいろ探してたら、
algol68 struct union esac でググって、
http://www.cs.virginia.edu/~evans/cs655-S00/Spring-1999/Slides/05a68_pasc.pdf
や http://page.inf.fu-berlin.de/~wolff/Algol68-OCCL.html
というのを見つけました。
20年ほど前に解説書を1冊読んだのですが、これを見て少し思い出してきました。
戸田さんのサンプルをalgol68で書くと、
STRUCT (
INT maindata,
STRUCT (
INT subdata,
[0:3] CHAR subtext
) subsets,
[0:79] CHAR maintext
) datasets;
でしょうか。一番 C と似てますね。(algol68 のプログラムの記述には2種類の文字が
必要なのでとりあえずキーワードや型名を大文字にしました)
union もありますが、これは C とずいぶん違う。C ではどの型のデータが入っている
かはプログラマが管理しますが、algol68 では処理系が管理します。
宣言:
UNION (INT,REAL) foo;
代入:
foo := 1.5;
foo := 123;
参照:
CASE foo IN
(INT i): print(("integer=",i)),
(REAL f): print(("real=",f))
ESAC
代入した型と違う型で参照しようにも方法が無い。i の有効範囲は , までなので
(REAL f)の後の式では使えません。f も逆に同じ。
print手続きの引数も任意の型のunionです。上記例では、STRUCT(STRING,INT)型や
STRUCT(STRING,REAL)型の表記です。
ちなみに ; は区切りでも終端でもなく演算子です。C の , 演算子と同意。
処理系をさわったことが無いだけに憧れの言語ですね。
ふた昔前の記憶で書いているので間違ってたらごめんなさい。
--
oo
> ということで、とりあえずWebで少しは判らないかと
> いろいろ探してたら、
> http://www.page.sannet.ne.jp/mnagai/msj/pgm_lang.htm
> なんていうページが出てきました。
> まあ、わりとよくできてるかな。
politically incorrectではありますが.
# 実際,読んであまり気分が良くないです.
> Pascalのところに、「Algol 60はその妹」とあるんですが、
> 「Algol 68は」の間違いじゃなかろうか。
姉も妹もsisterだけど,年齢から言えばAlgol 60が姉でしょうね.
OOTANI TAKASHI <tks...@anet.ne.jp> writes:
> algol68 struct union esac でググって、
> http://www.cs.virginia.edu/~evans/cs655-S00/Spring-1999/Slides/05a68_pasc.pdf
> や http://page.inf.fu-berlin.de/~wolff/Algol68-OCCL.html
> というのを見つけました。
http://dmoz.org/Computers/Programming/Languages/Algol_68/
というページがありました. Revised Reportもここからたどって読めます.
(恐ろしく読みにくいが…)
> union もありますが、これは C とずいぶん違う。C ではどの型のデータが入っている
> かはプログラマが管理しますが、algol68 では処理系が管理します。
Pascalの場合は「可変レコード」ですね(たぶん,unionという予約語を1つ
ケチった?). Algol68との大きな違いは,
・どの型のデータが入っているかを表す「タグ」を陽に書く.
type
nodetype = (interim, leaf);
node = record
case tag: nodetype of
interim: (left, right: ^node);
leaf: (value: integer);
end
・ところが,タグを省略することも出来るのだそうです(型システムの抜け穴).
type
node = record
case boolean of
false: (left, right: ^node);
true: (value: integer);
end
こっち(タグなしの可変レコード)は,Cのunionと機能的に同等です.
> 処理系をさわったことが無いだけに憧れの言語ですね。
上のページには,処理系もいくつか載っています.
前田敦司
>> Pascalのところに、「Algol 60はその妹」とあるんですが、
>> 「Algol 68は」の間違いじゃなかろうか。
>姉も妹もsisterだけど,年齢から言えばAlgol 60が姉でしょうね.
というか、
系譜的に言えば、PascalとAlgol 68が姉妹で、
共にAlgol 60の娘とするのが妥当なんじゃないか、
ということなんですけど。
#この発想で行くと、Algol 60は凄い「子沢山」になってしまう……
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
プログラムが書けるには程遠い状況ですが、
何となくalgol 68の雰囲気が解ってきたので、
http://www.lbm.go.jp/toda/comp/struct.html
を改訂してみました。
「COBOLからPL/Iへ」の部分は、状況証拠がかなり明確なんですが、
「C言語への影響」になってくると、「どっちの影響が強い」のか
明確で無くなってきますね。ちょっと歯切れの悪い書き方になってしまいました。
>ちなみに ; は区切りでも終端でもなく演算子です。C の , 演算子と同意。
algol系の「式と文を区別しない」発想の延長ですね。
Pascalはこの発想を捨てているので、
FORTRAN→Basic→PL/I→COBOL→Pascal→algol→Cという順で
学習してきた身としては、
algolのところでカルチャーショックを受けました^_^;
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
to...@lbm.go.jp writes:
> In article <u7k4rg...@anet.ne.jp> tks...@anet.ne.jp writes:
> 「C言語への影響」になってくると、「どっちの影響が強い」のか
> 明確で無くなってきますね。ちょっと歯切れの悪い書き方になってしまいました。
ちょっとそれますが、
Cと深い関係を持っているunixのもうひとつの主要言語である Bourne shell には
alogl68の影響が大きく見られます。if/then/elif/else/fi、case/in/esac は同一。
for/while/do/od はodがdoneにかわっただけ。(odコマンドが先にあったからか?)
キーワード名の一致だけでなく、Bourne shell で、
while read a,b
test a -gt 0
do foo bar $a $b
done < file
のように条件部分に複数の文/式をかけることも同じですし、
すべてのコマンド実行が別の面から見ると条件式であるのも式言語を思わせます。
program |
case "$opt" in
-format) pr ;;
*) cat ;;
esac | lpr
のように構造文がパイプの中で使えるのもこれらがalgol68では値を持つことと
似ているような気がします。
> http://www.lbm.go.jp/toda/comp/struct.html
> を改訂してみました。
そこから引用:
>COBOLの名前空間は全体で1つであり、メンバー変数の名前を個々の構造体ごとに
>変えねばならない。そして、構造体変数の代入は常に並び順照合である。
これは間違ってます。
>PL/Iでは、異なる構造体に同一名のメンバーが属することを許容し
>(むしろ同一構造の構造体には同一メンバ名を用いることを推奨し)、
>代入に際して名前で照合する「BY NAME」指定を導入した。
と書いてあるPL/Iと同じです。同じ名前の要素の参照は、「要素名 OF 親の名」
で参照します。要素名がプログラム中でユニークなら「OF 親の名」は省略可。
名前で照合して代入や計算するのは CORRESPONDING 。
>ちなみに、COBOLで構造の異なる構造体変数へ代入する場合は、一旦バイト列に
>分解して頭から変数に切り直すという恐ろしい仕様(ファイル入出力のバッファ
>という発想からすれば自然か?)になっている。
これはちょっと意味がわかりません。構造の異なる構造体変数への代入は
ごく普通に親の名前を使って MOVE すればできるのでは?
COBOL,PL/Iのリファレンスは、http://www.jbooksrv.yamato.jp.ibm.com/ がいいです。
--
oo
> Cと深い関係を持っているunixのもうひとつの主要言語である Bourne shell には
> alogl68の影響が大きく見られます。if/then/elif/else/fi、case/in/esac は同一。
> for/while/do/od はodがdoneにかわっただけ。(odコマンドが先にあったからか?)
なるほどね。ただBourne shellはUnix V7からだからCよりはかな~り後
の言語という印象です。V6までのshellは全然言語っぽくない。
BCPLはもうおぼえている人がいないのかな… 久野
In article <uu17rw...@anet.ne.jp> tks...@anet.ne.jp writes:
>> http://www.lbm.go.jp/toda/comp/struct.html
>> を改訂してみました。
>そこから引用:
>>COBOLの名前空間は全体で1つであり、メンバー変数の名前を個々の構造体ごとに
>>変えねばならない。そして、構造体変数の代入は常に並び順照合である。
>これは間違ってます。
情報ありがとうございます。
ただ、私の知り得る情報を総合した限りでは、
「間違っている」のではなく「情報が古い」のではないかと思うのですが、
如何でしょうか?
実は私のCOBOLに関する知識は、(恐ろしいことに)1982年で停まっておりまして、
従って、「第3次規格」(ANSI 1985, ISO 1985, JIS 1988)以前なのです。
使っていた教科書にも、
「構造化プログラミングを導入する改訂の規格化が進められている」と
コラムの中で触れられていて、
手続き部の書き方に関する簡単な例が挙げられているだけで、
詳細な内容はありません。
>>PL/Iでは、異なる構造体に同一名のメンバーが属することを許容し
>>(むしろ同一構造の構造体には同一メンバ名を用いることを推奨し)、
>>代入に際して名前で照合する「BY NAME」指定を導入した。
>と書いてあるPL/Iと同じです。同じ名前の要素の参照は、「要素名 OF 親の名」
>で参照します。要素名がプログラム中でユニークなら「OF 親の名」は省略可。
>名前で照合して代入や計算するのは CORRESPONDING 。
というのも、発想的にはalgol系の世界から持ってきた
(直接にはPL/Iから逆輸入した?)と考えられる内容なので、
第3次規格の際に導入されたのではないかとニラんでいるのですが、
裏付ける情報が全く得られていません。
どこかに、第3次規格の際の改定内容の詳細を
簡潔にまとめたテキストって無いでしょうか?
>>ちなみに、COBOLで構造の異なる構造体変数へ代入する場合は、一旦バイト列に
>>分解して頭から変数に切り直すという恐ろしい仕様(ファイル入出力のバッファ
>>という発想からすれば自然か?)になっている。
>これはちょっと意味がわかりません。構造の異なる構造体変数への代入は
>ごく普通に親の名前を使って MOVE すればできるのでは?
「分解」というより「展開」と表現した方が良かったかな?
例えば、
01 ORGNSTRC.
10 ORGNTEXT1 PIC X(4).
10 ORGNTEXT2 PIC X(6).
と
01 DESTSTRC.
10 DESTTEXT1 PIC X(6).
10 DESTTEXT2 PIC X(4).
があって、
ORGNTEXT1の内容が「1234」、ORGNTEXT2の内容が「ABCDEF」だったときに
MOVE ORGNSTRC TO DESTSTRC.
とすると、
DESTTEXT1の内容は「1234AB」、DESTTEXT2の内容は「CDEF」になる
(つまり、メンバ変数間の区切りが無視される)ということです。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
とりあえず、元の話題に関連するところでは、
(1)「構造体」という概念はBCPLには無い
データ型が無い(後述)ので、
種類の異なるデータを1つの配列(ベクタ)に混在させることはできますが、
要素を「指標数値」ではなく「名前」で識別するというものはありません。
オフセット値を定数名(マニフェスト定数)として定義することによって、
実質的に「名前による要素の識別」を行うことはできますが、
構造体のようにコンパイラが自動的にオフセット値を計算するのではなく、
プログラマがオフセット値を計算してプログラムに記述せねばなりません。
(2)C言語がPL/Iから直接受け継いだと思われる特徴はBCPL起源ではない
注釈に“/* */”を使う流儀ではありません。
“//”から行末までが注釈です……って、
最近のC++とかに追加された注釈の書法と同じだ^_^;
また、“;”は分離記号です。但し、行末も分離記号です。これはビックリ。
正確には、行の最後のトークンが文末に位置し得るものであれば分離記号で、
文末に位置し得ないトークンで終わっていたら次行に継続します。
何ちゅう投げ槍な仕様だ……
================================
元の話題と直接関係ない点で興味を引いたところとしては、
(3)データ型の区別が無い
CPLからBCPLへの最大の変更点は、この点なんだそうです。
区別が無いと言っても、AWKやPerlのように、
"123"という文字列が数式に現れたら「123」という数値になる
というような「人間寄り」の「区別の無さ」ではありません。
データは言語レベルでは内部表現としてのみ意味があり、
その内部表現にどういう意味を持たせるかはプログラマ次第
という意味で「機械寄り」の「区別の無さ」です。
まあ、アセンブリプログラマにとっては素直な発想ですし、
おそらくこの考え方がB言語に引き継がれ、
いくら何でもそれじゃ不便だというので
C言語で揺り戻されたということなんでしょうね。
(B言語の詳細を知らないので、その部分は推測です)
とはいえ、システム記述の上で重要な
「文字型データは、その内部表現を値とする整数型データでもある」
「アドレスデータ(ポインタ)は、
その内部表現を値とする整数型データと相互に変換できる」というような
「データの二面性」はC言語にまで引き継がれたわけです。
ちょっと気になったのが、
C言語の「charとshort intとlong int」に相当する区別が無いこと、
つまり如何なるデータも同一量の記憶域を占有するということです。
この仕様ってCPUを選んでしまうんじゃないでしょうか?
なお、文字列に関しては、1配列要素に何文字かを詰込んで取扱う
ライブラリが標準で準備されています。
C言語やPascalと違って、詰込まれた文字列に対する操作を
配列操作と同じ書式で行うことはできず、専用のライブラリを要します。
(4)IF構造に相当するものがELSEの有無で区別されている
IFにはTHEN節のみでELSE節がありません。
THEN節とELSE節が共存する場合はIFに代えてTESTを使います。
こういう言語って初めて見ました。
ちなみに、UNLESS~DOというのがあって、
ELSE節だけあってTHEN節が無い状況に相当します。
(5)FORループの制御変数のスコープは、そのループ内
(FORTRANやPL/IのDOループに相当)
「ループを飛出した時の値を参照する」技法が使えないということです。
そのくせ、制御変数の値を途中で変えてしまって、
繰り返し回数に影響を与えることは認められています。変なの。
制御変数はFORループの形式に記述することによって宣言され、
改めて変数を宣言する必要は無い
……というより、改めて宣言してはならないことになっています。
(6)“A < B < C”という条件式が自然言語の数式と同じ意味を有する
つまり、「A < B」AND「B < C」という意味になります。
これも初めて見た……
(7)配列(ベクタ)を宣言すると、同名の単純変数も同時に確保され、
当該配列へのポインタで初期化される
わけのわからん無駄な仕様ですね。
当該配列へのポインタを値とする定数名とするのが素直なんですけど。
(C言語は、まさにそう)
(8)インラインの手続きが、親手続きの局所変数にアクセスできない
アクセスが必要な場合はグローバル変数を使うことになりますが、
親手続きの中で定義すれば、親手続きの外では見えないので、
スコープ的には素直に親子での変数共有になります。
しかし、変数のメモリ管理(寿命など)は、あくまでグローバルです。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
to...@lbm.go.jp wrote:
> M.Richards and C.Whitby-Strevens(和田英一訳)
> BCPL言語とそのコンパイラ(共立出版1985)ISBN4-320-02245-9
> (3)データ型の区別が無い
「BCPLは型無し言語である」というのは有名ですよね。
> データは言語レベルでは内部表現としてのみ意味があり、
> その内部表現にどういう意味を持たせるかはプログラマ次第
> という意味で「機械寄り」の「区別の無さ」です。
要は word ですよね。
> ちょっと気になったのが、
> C言語の「charとshort intとlong int」に相当する区別が無いこと、
> つまり如何なるデータも同一量の記憶域を占有するということです。
> この仕様ってCPUを選んでしまうんじゃないでしょうか?
PDP-11などでは困りますが。
多くのメインフレームのようなワードマシンでは困らなかったの
だとおもいます。
> (7)配列(ベクタ)を宣言すると、同名の単純変数も同時に確保され、
> 当該配列へのポインタで初期化される
>
> わけのわからん無駄な仕様ですね。
> 当該配列へのポインタを値とする定数名とするのが素直なんですけど。
> (C言語は、まさにそう)
定数オペランドアドレスにアクセスするアドレッシングモードがない
計算機を想定していたのでは?(正確には、アドレス空間全体は
アクセスできない)。最近ではCASLくらいですがそんなのは。
そういうCPUでのアセンブラのお作法に引きずられた。
(すみません。思いつきです)
SAITOH akinori <sai...@ist.osaka-u.ac.jp> writes:
> to...@lbm.go.jp wrote:
> > (7)配列(ベクタ)を宣言すると、同名の単純変数も同時に確保され、
> > 当該配列へのポインタで初期化される
> >
> > わけのわからん無駄な仕様ですね。
> > 当該配列へのポインタを値とする定数名とするのが素直なんですけど。
> > (C言語は、まさにそう)
>
> 定数オペランドアドレスにアクセスするアドレッシングモードがない
> 計算機を想定していたのでは?(正確には、アドレス空間全体は
> アクセスできない)。最近ではCASLくらいですがそんなのは。
> そういうCPUでのアセンブラのお作法に引きずられた。
> (すみません。思いつきです)
これは、
> > データは言語レベルでは内部表現としてのみ意味があり、
> > その内部表現にどういう意味を持たせるかはプログラマ次第
> > という意味で「機械寄り」の「区別の無さ」です。
>
> 要は word ですよね。
こっちと関係があるのではないかと思います。
配列宣言でその配列へのポインタも用意しておくことで、配列というデー
タ型をコンパイラが覚えておく必要が無くなります。
数 KB 程度のメモリで動作するコンパイラの場合、データ型が“word”
だけで済む(=データ型を区別する必要が無い)のとそうでないのとで
は、コンパイラのサイズが相当変わってきます。
うろ覚えですが、μPLAN も同様な仕様だったと思います。
--
片山@PFU
データ型が無いことを除けば、C言語にソックリですね。
algol系の「“=”は比較、代入は“:=”」という
伝統(BCPLも継承している)に逆らって、
「“=”は代入、比較は“==”」としているのも同じです。
代入演算子が逆順(“+=”ではなく“=+”)とか、
ビットごと論理と2値論理の区別が無いとかいったあたりは、
教科書類に「初期のC言語はこうだった」と書いてあるそのまんま。
注釈を「/* */」で表記することや、
“;”を分離記号ではなく終端記号として用いることも、
B言語経由でPL/IからC言語に継承されたようです。
In article <qkpoexs...@dash.tokyo.pfu.co.jp> ka...@pfu.fujitsu.com writes:
>> > (7)配列(ベクタ)を宣言すると、同名の単純変数も同時に確保され、
>> > 当該配列へのポインタで初期化される
>> > わけのわからん無駄な仕様ですね。
>> > 当該配列へのポインタを値とする定数名とするのが素直なんですけど。
>> 定数オペランドアドレスにアクセスするアドレッシングモードがない
>> 計算機を想定していたのでは?
だからって、「変数」としてアクセス可能にする必要は無いでしょう。
変数と同じメモリ領域に値を保持するとしても、「無名の変数」にして
プログラムからはアクセスできなくする方が素直だと思います。
即値定数や文字列定数の値を、CPUの都合で、
変数と同じメモリ領域に保持するのと同じことです。
>これは、
>> > データは言語レベルでは内部表現としてのみ意味があり、
>> > その内部表現にどういう意味を持たせるかはプログラマ次第
>> > という意味で「機械寄り」の「区別の無さ」です。
>> 要は word ですよね。
>こっちと関係があるのではないかと思います。
>配列宣言でその配列へのポインタも用意しておくことで、配列というデー
>タ型をコンパイラが覚えておく必要が無くなります。
よく解りません……
配列は「データ型」ではありませんよね。
コンパイラにとっては、
「宣言されただけの記憶域をシステムが確保する」というのが
配列というオブジェクトの本質であり
(この「確保」がシステムにとって一番の負担ですよね)、
それは、対応するポインタ変数を確保するかどうかに関係ありません。
そして、いずれにしても配列名は
「確保された記憶域のアドレスという意味を有するword型のデータ」であり、
今問題になっているのは、
それが「定数」なのか「変数」なのかという違いに過ぎません。
ちなみに、B言語には、この妙な仕様は継承されていないようです。
(B言語の処理系は、ネイティブコードを吐くコンパイラが記述できないような
貧弱な環境のために開発されている)
やはり、必然性の無い仕様なのではないでしょうか?
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
<bjpl36$gfg$1...@bluegill.lbm.go.jp>の記事において
to...@lbm.go.jpさんは書きました。
toda> In article <qkpoexs...@dash.tokyo.pfu.co.jp> ka...@pfu.fujitsu.com writes:
toda> >> > (7)配列(ベクタ)を宣言すると、同名の単純変数も同時に確保され、
toda> >> > 当該配列へのポインタで初期化される
toda> >> > わけのわからん無駄な仕様ですね。
toda> >> > 当該配列へのポインタを値とする定数名とするのが素直なんですけど。
toda> >> 定数オペランドアドレスにアクセスするアドレッシングモードがない
toda> >> 計算機を想定していたのでは?
toda> だからって、「変数」としてアクセス可能にする必要は無いでしょう。
toda> 変数と同じメモリ領域に値を保持するとしても、「無名の変数」にして
toda> プログラムからはアクセスできなくする方が素直だと思います。
BCPL の都合上 a!i と書いたら a にアクセスしてしまうので,
# BCPL のバージョンにより配列の要素参照はいろいろな構文があるので
# すが, ここでは a!i を使います.
「無名の変数」の意味はないでしょう (配列名をその変数の名前にして
しまえばいいわけで). まぁ, 「変数」である必要はよくわかりませんが
(「定数」でもいいので).
toda> >これは、
toda> >> > データは言語レベルでは内部表現としてのみ意味があり、
toda> >> > その内部表現にどういう意味を持たせるかはプログラマ次第
toda> >> > という意味で「機械寄り」の「区別の無さ」です。
toda> >> 要は word ですよね。
toda> >こっちと関係があるのではないかと思います。
toda> >配列宣言でその配列へのポインタも用意しておくことで、配列というデー
toda> >タ型をコンパイラが覚えておく必要が無くなります。
toda> よく解りません……
toda> 配列は「データ型」ではありませんよね。
toda> コンパイラにとっては、
toda> 「宣言されただけの記憶域をシステムが確保する」というのが
toda> 配列というオブジェクトの本質であり
toda> (この「確保」がシステムにとって一番の負担ですよね)、
toda> それは、対応するポインタ変数を確保するかどうかに関係ありません。
ただ, 対応するポインタ変数を確保することによって「コンパイラが配
列の大きさを意識しなくていい」ということは言えると思います.
これは 2次元以上の配列になると影響してくるんですが, C で a[M][N]
という配列 (M, N は定数) を確保したときに a[i][j] をアクセスしよ
うとすると, 実質的に *(a[0] + i*N + j) という計算をすることになり,
このため N を記憶しておく必要があります (場合によっては i*N とい
う乗算も必要). ところが, BCPL では同じ配列に対して a の分に加えて
a!0~a!(M-1) の分も確保します (a の内容は a!0 のアドレス, a!i の
内容は a!i!0 のアドレス). こうすると a!i!j のアクセスに必要な処理
は C で書くと *(*(a + i) + j) となり, N の値を記憶する必要はなく
なります (しかも乗算も不要).
toda> そして、いずれにしても配列名は
toda> 「確保された記憶域のアドレスという意味を有するword型のデータ」であり、
toda> 今問題になっているのは、
toda> それが「定数」なのか「変数」なのかという違いに過ぎません。
BCPL にとっては「変数」か「定数」かはどうでもよくって, 単に「メモ
リ上に存在すればいい」ということです.
toda> やはり、必然性の無い仕様なのではないでしょうか?
「変数」である必然性はないですね.
でも, 「メモリ上にポインタとして存在する」というのは便利だと思い
ますよ. 実際, C だってまともに 2次元配列を扱う (ex. 行列演算) ラ
イブラリを作ろうと思ったら同様の方法を採るしかないわけですし.
--
名古屋大学大学院 情報科学研究科 計算機数理科学専攻
小野 孝男
そういうアクセス法が必要だとプログラマが判断した場合に、
明示的にプログラミングによって確保するとする方が、
BCPLの哲学にも合っているような気がします。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
Dennis M. Ritchie, The Development of the C Language,
http://www.cs.bell-labs.com/who/dmr/chist.html
では、
C言語で型の概念を再導入した3つの動機のうち2つが、
この問題に関連するものだと述べていますね。
(残りの1つは浮動小数点関連)
バイト境界で文字が並んだ文字列を取扱う際、
機械語のバイトアドレッシングを直接使えば素直に取扱えるのに、
わざわざワード境界にunpackして取扱うという
馬鹿げた作業が必要になるというのが1つ、
プログラム上ではアドレスをワード単位で取扱い、
それをポインタとして用いる段階で
逐一バイト単位に換算せねばならないというのが1つです。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
>> (2)C言語がPL/Iから直接受け継いだと思われる特徴はBCPL起源ではない
>>
>> 注釈に“/* */”を使う流儀ではありません。
>> “//”から行末までが注釈です……って、
手元の資料では
BCPL /*...*/
BCPL |*...*|
BCPL \*...*\
BCPL //...
BCPL ||...
BCPL \\...
なんですが、これガセネタだったんでしょうか?
#BCPLにもバージョンがあったんかもしれませんが
--
kabe
<ka...@sra-tohoku.co.jp>さんの<750211200...@sra-tohoku.co.jp.msgid>から
http://web.cs.mun.ca/~ulf/pld/surface.html
には、かべさんの書いたものが載ってますね。
--
R4000 2.2 mailto:ta...@kc5.so-net.ne.jp
>#BCPLにもバージョンがあったんかもしれませんが
方言(独自拡張)が多数あったようですよ。
私が参照したBCPLの教科書にも、浮動小数点対応とか
ライブラリ参照に絡んだ拡張に触れた部分がありましたし。
戸田 孝@滋賀県立琵琶湖博物館
to...@lbm.go.jp
間違って編集前に出してしまいました。
SAITOH akinori wrote:
>
> to...@lbm.go.jp wrote:
>>>>定数オペランドアドレスにアクセスするアドレッシングモードがない
>>>>計算機を想定していたのでは?
>>だからって、「変数」としてアクセス可能にする必要は無いでしょう。
>>変数と同じメモリ領域に値を保持するとしても、「無名の変数」にして
>>プログラムからはアクセスできなくする方が素直だと思います。
>>即値定数や文字列定数の値を、CPUの都合で、
>>変数と同じメモリ領域に保持するのと同じことです。
必要はないですが、コンパイラが楽になりますね。
identifierが配列名だった場合の処理が省略できる。
BCPLの作者のメンタリティが戸田さんと異なっていて、異なる
デシジョンをしたというだけだとおもいますが。