以下のような program を作成し
#include <stdio.h>
typedef struct tTest {
int iDummy ;
} tTest ;
tTest *ptMode1 ;
main ()
{
ptMode1->iDummy = 15 ;
}
以下のようにコンパイルして、
$ gcc test5.c
実行すると、
$ ./a.out
セグメンテーション違反です
と表示されてしまいます。 特に変なところはないと思うのですが、
どこか間違っていますでしょうか?
環境 : Vine 3.1 + gcc-3.3.2
以上、よろしくお願いします。
--
K.Moriyama
On Tue, 22 Feb 2005 23:36:33 +0900, K.Moriyama <for...@ma.kcom.ne.jp>
wrote:
> 森山と申します。
> 以下のような program を作成し
>
> #include <stdio.h>
>
> typedef struct tTest {
> int iDummy ;
> } tTest ;
>
> tTest *ptMode1 ;
>
> main ()
> {
> ptMode1->iDummy = 15 ;
> }
変数ptMode1が初期化されていません。
動くようにするためには:
typedef struct tTest {
int iDummy ;
} tTest ;
tTest *ptMode1 ;
int main (int srgc, char* argv[])
{
tTest Mode1;/* define tTest type local object Mode1 */
ptMode1 = &Mode1;/* get address of Mode1 */
ptMode1->iDummy = 15 ;
return(0);
}
あるいは:
#include <stdlib.h>
typedef struct tTest {
int iDummy ;
} tTest ;
tTest *ptMode1 ;
int main (int srgc, char* argv[])
{
ptMode1 = (tTest*)malloc(sizeof(tTest));
/* allocate memory to tTest type object */
ptMode1->iDummy = 15 ;
return(0);
}
としてちゃんと構造体を用意して、それへのポインタで
ポインタ型変数を初期化してから使わなければいけません。
初期化していない変数がメモリのどこを指しているかは保証されません。
ちなみに最初の方法はあまり使いません。
関数が終了するとローカル変数に割り当てられた領域はなくなってしまうので。
この例ではmain関数内なのであまり問題はないと思いますが。
あとmain関数の引数と返り値の型はちゃんと宣言しましょう。
--
http://www.nerimadors.or.jp/~kando/
ka...@nerimadors.or.jp
kando_t...@hotmail.com : MSN Messenger
In article <opsmltdb...@news.media.kyoto-u.ac.jp>, 神戸隆行<ka...@nerimadors.or.jp> writes
> > typedef struct tTest {
> > int iDummy ;
> > } tTest ;
> > tTest *ptMode1 ;
初期化でで解決するなら、
tTest tTest0;
tTest *ptMode1 = &tTest0;
ですかね。1 line で
tTest tTest0,*ptMode1 = &tTest0;
でもいくのか。
> ptMode1 = (tTest*)malloc(sizeof(tTest));
> /* allocate memory to tTest type object */
まぁ、もちろん、これが正当なわけだけど。
以下は、どうでもいい戯言です。
代わりのシンタックスとして、
tTest& *ptMode1;
(わけわからん)
C++ っぽく、
ptMode1 = tTest();
new でもいいか、
ptMode1 = tTest->new;
GCC の拡張っぽく、
ptMode1 = typed_malloc(tTest);
(typeof (ptMode1)) p = ptMode1 ;
とかできたりするとか~
---
Shinji KONO @ Information Engineering, University of the Ryukyus
河野真治 @ 琉球大学工学部情報工学科
神戸さん、河野さん、ありがとうございます。
ポインタ型で宣言した後に、領域の確保を行うのですね。
# そう思って、入門書を読むと[ 実行時に、malloc 関数を使用して
# 記憶領域を確保...]とさらっと記載されていました。うーん、例文
# くらい掲載してほしかった...あれ、例文あるな~巻末に...
On Wed, 23 Feb 2005 00:01:49 +0900
神戸隆行 <ka...@nerimadors.or.jp> wrote:
> tTest Mode1;/* define tTest type local object Mode1 */
> ptMode1 = &Mode1;/* get address of Mode1 */
> あるいは:
> ptMode1 = (tTest*)malloc(sizeof(tTest));
On Tue, 22 Feb 2005 15:43:46 +0000 (UTC)
ko...@ie.u-ryukyu.ac.jp (Shinji KONO) wrote:
> 初期化でで解決するなら、
>
> tTest tTest0;
> tTest *ptMode1 = &tTest0;
>
> ですかね。1 line で
>
> tTest tTest0,*ptMode1 = &tTest0;
> 代わりのシンタックスとして、
> tTest& *ptMode1;
> (わけわからん)
> C++ っぽく、
> ptMode1 = tTest();
> new でもいいか、
> ptMode1 = tTest->new;
> GCC の拡張っぽく、
> ptMode1 = typed_malloc(tTest);
> (typeof (ptMode1)) p = ptMode1 ;
又、色々な方法のご教示ありがとうございます。
で、教えてもらった内容を元に、以下のような program を作成しました。
# 元々、以下の program 作成が目的で、先の program はエラーと
# なったことから、エラーの切り分けように作成したものです。
#
# 内容は、ユーザが宣言した構造体型ポインタに体して、別に設定している
# 構造体型ポインタのアドレスを設定するというものです。
#include <stdio.h>
typedef struct tSample {
int iDummy ;
int iDummy2 ;
} tSample ;
tSample gSystemArea , *pgSystem = &gSystemArea ;
int biSetPointer ( int *piTemp )
{
*piTemp = (int)pgSystem ;
return ( 1 ) ;
}
int main ( int srgc, char* argv[] )
{
tSample *pgUser ;
int biDone ;
pgUser = (tSample*)malloc(sizeof(tSample)) ;
pgUser->iDummy = 15 ;
pgSystem->iDummy = 30 ;
printf("pgUser->iDummy = %d\n" , pgUser->iDummy ) ;
printf("pgSystem->iDummy = %d\n" , pgSystem->iDummy ) ;
biDone = biSetPointer ( &pgUser ) ;
printf("pgUser->iDummy = %d\n" , pgUser->iDummy ) ;
printf("pgSystem->iDummy = %d\n" , pgSystem->iDummy ) ;
return(0) ;
}
これをコンパイルすると、
$ gcc dummy3.c
dummy3.c: 関数 `main' 内:
dummy3.c:34: 警告: 互換性のないポインタ型からの引数 1 個の `biSetPointer' を渡しますです
と、表示されます。一応コンパイルは出来るのですが、あまり気持のいい
ものでは有りません。
本来は以下の部分を、
biDone = biSetPointer ( &pgUser );
以下のようにすべきなのでしょうが、
biDone = biSetPointer ( (int * )&pgUser );
この部分は、変更せずに( &pgUser )のままで、関数側で
対処する方法はないものでしょうか? ご存じの方がいましたら
ご教授願います。
--
K.Moriyama
> $ gcc dummy3.c
> dummy3.c: 関数 `main' 内:
> dummy3.c:34: 警告: 互換性のないポインタ型からの引数 1 個の `biSetPointer' を渡しますです
コメント等を省いているので、行数は実際と異なっています。
ちなみに英語では、以下のようになっています。
dummy3.c: In function `main':
dummy3.c:34: warning: passing arg 1 of `biSetPointer' from incompatible pointer type
以上、よろしくお願いします。
--
K.Moriyama
ポインタのキャスト(型変換)について誤解があるようです。
typedef Struct tHoge {
int i;
} Hoge;
について
Hoge* pHoge
と
int* pI
の間のキャスト
(Hoge*)pI
と
(int*)pHoge
はどちらもそれぞれがまともに初期化されていたとしても
一般にまともな結果になりません。
pIが
pHogeで指されているHoge型オブジェクトのiというメンバ
を指すようにしたければ、
pI = &(pHoge->i)
あるいは
pI = &((*(pHoge)).i)
とする必要があります。
注意:
pHogeがmalloc()で返されたポインタ値である場合、pHogeをfree()で開放した後は
上記のような方法で初期化したpIの指している領域が何を指しているかは神の味噌汁…。
関数側で云々と言うより,そもそも biSetPointer で何をしたいのかをもう少し明確にしな
いと的確なアドバイスは得られないのではと思いますが。
私自身ほとんど初級者レベルではありますが,私にはbiSetPointerの意味が理解できませ
ん。
警告を消すだけならpgUserはもともとポインタなので,&なんかつけずとも
biDone = biSetPointer ( (int * )pgUser );
とする方が自然なような気もしますが,やろうとしていることがよく分からないので?で
す。
--
******************************
keizi kounoike
******************************
On Thu, 24 Feb 2005 16:53:16 +0900
<koun...@mbh.nifty.com> wrote:
> 関数側で云々と言うより,そもそも biSetPointer で何をしたいのかをもう少し明確にしな
> いと的確なアドバイスは得られないのではと思いますが。
>
> 私自身ほとんど初級者レベルではありますが,私にはbiSetPointerの意味が理解できませ
> ん。
確かにおっしゃる通りですね。
元々は、装置の制御用にメーカが提供しているライブラリに
単を発しています。
説明では、あらかじめ以下の構造体を定義して有るので、
static struct tGroupName {
int iDummy ;
int iDummy2 ;
} ; < ここに名前が無いのは変なのですが、
メーカ説明では、何も記載されて
いません。
ユーザで、以下のように宣言し、
static struct tGroupName *pgUser ;
以下のように関数を使用する事により、
functionName ( &pgUser ) ;
以下のように値を得る事が出来る。
iUserVar = pgUser->iDummy ;
という説明になっているのです。
# メーカの説明では、ユーザが定義した構造体型ポインタ変数の
# 領域確保については説明が無く、サンプルプログラムでも領域確保の
# 記述は有りません。又、ソースは公開されていません。
# 尚、上記で使用している変数名等は、実際の名称とは異なります。
で、上記ライブラリの動作を調べると、関数を使用した時にユーザが
定義した変数に値を返すのではなくて、あらかじめ確保してある領域の
ポインタを返すような動作になっているのです。
それで、関数側でどうゆう処理をしているのかと、興味を持った
次第なのです。
# ちなみにコンパイラ自体もメーカ提供のもので、NECのPC-9801用
# MS-DOSで使用する物です。
--
K.Moriyama
> ユーザで、以下のように宣言し、
> static struct tGroupName *pgUser ;
> 以下のように関数を使用する事により、
> functionName ( &pgUser ) ;
> 以下のように値を得る事が出来る。
> iUserVar = pgUser->iDummy ;
> という説明になっているのです。
そういうことであれば、単に
int biSetPointer (tSample **piTemp)
{
*piTemp = pgSystem;
return 1;
}
という感じでいいんではないかと。
余談ではありますが、ここはキャストが必要になる場面ではないでしょう。
キャストが必要になるようなコードはたいていどこか疑わしいと私は思ってます。
# 絶対ダメとか言うほど現実を知らないわけでもないですが。
----
URI http://saito.s4.xrea.com/
e-mail sa...@s4.xrea.com
In article <20050224225102....@ma.kcom.ne.jp>, "K.Moriyama" <for...@ma.kcom.ne.jp> writes
> 説明では、あらかじめ以下の構造体を定義して有るので、
>
> static struct tGroupName {
> int iDummy ;
> int iDummy2 ;
> } ; < ここに名前が無いのは変なのですが、
> メーカ説明では、何も記載されて
> いません。
構造体の宣言なので、特に変ではないです。でも、このstatic
は無意味だと思う。
% gcc -Wall -c /tmp/aho1.c
/tmp/aho1.c:5: warning: useless keyword or type name in empty declaration
とコンパイラも言ってます。
> ユーザで、以下のように宣言し、
> static struct tGroupName *pgUser ;
これは理解できます。
> 以下のように関数を使用する事により、
> functionName ( &pgUser ) ;
> 以下のように値を得る事が出来る。
> iUserVar = pgUser->iDummy ;
> という説明になっているのです。
なるへそ。
> で、上記ライブラリの動作を調べると、関数を使用した時にユーザが
> 定義した変数に値を返すのではなくて、あらかじめ確保してある領域の
> ポインタを返すような動作になっているのです。
> それで、関数側でどうゆう処理をしているのかと、興味を持った
> 次第なのです。
> # ちなみにコンパイラ自体もメーカ提供のもので、NECのPC-9801用
> # MS-DOSで使用する物です。
malloc して返すなら free しろって書いてあると思うので、きっと
static な領域をさしているんだろうな。昔のUnixにも、そんなAPI
あったような....
static struct tGroupName sUser ;
void functionName ( struct tGroupName **pgUser )
{
*pgUser = &sUser;
}
とか。あるいは、free するルーチンを使って、
void openGroupName ( struct tGroupName **pgUser )
{
*pgUser = (struct tGroupName *)malloc(sizeof(struct tGroupName *)) ;
}
void closeGroupName ( struct tGroupName **pgUser )
{
free(*pgUser);
}
みたいな。** が理解できるかどうかが問題ですけど...
僕は、struct は、typedef と必ず併用しろって教えてます。
typedef struct tGroupName {
int iDummy ;
int iDummy2 ;
} TGROUPNAME, *TGROUPNAME_PTR;
としてやれば、
static TGROUPNAME sUser ;
void functionName ( TGROUPNAME_PTR *pgUser )
{
*pgUser = &sUser;
}
ってな感じ。** 使えない人には便利?
In article <opsmnlzh...@news.media.kyoto-u.ac.jp>, 神戸隆行<ka...@nerimadors.or.jp> writes
> Hoge* pHoge
> と
> int* pI
> の間のキャスト
> (Hoge*)pI
> と
> (int*)pHoge
> はどちらもそれぞれがまともに初期化されていたとしても
> 一般にまともな結果になりません。
これは、思い違いじゃない? (void*)にキャストするってのは、割
りとあるわけだし。
あぁ、そうか。Hoge の最初のint member にアクセスするのに、pI
にキャストしてもうまくいくとは限らないってことね。そういうア
ーキテクチャってあるのかな?
なにも保証されていないという意味では
「まともな結果」とは言い難いのでは?
プリミティブな型へのポインタならまだしも、
構造体ではパディングの影響もあります。
実際的には例のような状況でパディングするコンパイラは
めったにないとは思いますが規格では規定されていません。
想定されているアライン境界でしかメモリアクセスを許さない
アーキテクチャでは致命的な問題につながる可能性もありそうです。
----
齊藤@生涯一趣味プロ
まぁ、もとの話とはずれているんで、どうでもいいんですが...
In article <4HmTd.8$mh...@news1.dion.ne.jp>, 齊藤 敦志<sa...@s4.xrea.com> writes
> プリミティブな型へのポインタならまだしも、
> 構造体ではパディングの影響もあります。
先頭と終りでは、それはないはずです。
> めったにないとは思いますが規格では規定されていません。
これって、
struct packet {
int length;
int data[1];
}
とかって規格的にどうなのみたいな話で前に出ていたような気がします。
確かに決まってないとかいう話だった。
構造体をbinary formatに対応させるとかは結構ありますよね。特
に、異なるアーキテクチャ間で実メモリで通信するような場合。
Virtual Machine みたいな感じかな。コンパイラ・ディレクティブ
で逃げるっていう手もあるんだけど、packed struct とか欲しい気
もします。なんか COBOL みたいだが...
> 想定されているアライン境界でしかメモリアクセスを許さない
> アーキテクチャでは致命的な問題につながる可能性もありそうです。
PS2 (Linux)が、そういうアーキテクチャだったりします。なんだ
けど、これがcastしまくりなライブラリがついていたりするんです。
もう、楽しくってしょうがないです。
> > 想定されているアライン境界でしかメモリアクセスを許さない
> > アーキテクチャでは致命的な問題につながる可能性もありそうです。
>
> PS2 (Linux)が、そういうアーキテクチャだったりします。なんだ
> けど、これがcastしまくりなライブラリがついていたりするんです。
> もう、楽しくってしょうがないです。
PS2にかぎらず、無印68000、PowerPC、SPARCあたりもアーキテクチャとしては
同様ですね。
サンプルコード
#include<stdio.h>
union hoge
{
char c[5];
long L;
} a = {1,2,3,4,5};
int main()
{
printf("%8lX\n",*(long*)&a.c[1]);
}
Mac や SPARC では Segmentation fault になります。
x86 は黙って 05040302 という結果を出します。
========================================================================
飯嶋 浩光 / でるもんた・いいじま http://www.ht.sakura.ne.jp/~delmonta/
IIJIMA Hiromitsu, aka Delmonta mailto:delm...@ht.sakura.ne.jp
x86でも8088以外なら、「ちょっと黙って」結果を出しているわけですね。
一応ペナルティがありますんで。
--
___ わしは、山吹色のかすてーらが大好きでのぅ
[[o o]] ふぉっふぉっふぉ
'J' 森下 お代官様 MaNMOS 英夫@ステラクラフト
PGP Finger = CD EA D5 A8 AD B2 FE 7D 02 74 87 52 7C B7 39 37
In article <squhdk1...@stellar.co.jp>, man...@stellar.co.jp (Hideo "Sir MaNMOS" Morishita) writes
> x86でも8088以外なら、「ちょっと黙って」結果を出しているわけですね。
> 一応ペナルティがありますんで。
ところがさ...
最近は、キャッシュ経由でバスアクセスで、一旦キャッシュに入っ
てしまえば、alignment なんて関係ないようです。そりゃそうだ、
アドレスってのはキャッシュのタグにすぎないわけだから。授業で
alignmentのdemonstrationする簡単なプログラムを書いたりするわ
けですけど、全然差が出なくなりました。
PS2とかは古い方になるわけだね。
むしろキャッシュに入るかどうかの方がクリティカルなので、構造
体とかはpackして全体のサイズを縮めた方が良いのだと思う。
OSの授業のプログラムとかも、すぐcompile通らなくなるし~
通っても「意図した状況にならない」っての良くある。がんがん
変わるところが面白いんですけどね。Linux, OS-X, Windows...
PS2...
最近、Solaris をいじれないんでつまらん。またいれようかな。
Linux系だとBUS errorじゃないんですか?
Sparc SolarisだとBUS errorなんです。
#MacもSparcも使ってるけどLinuxはx86しかないんです。
あっりゃぁ、そうですよね。Cだとポータビリティ考えて、絶対にアライメン
トは揃えるプログラムを書くので、逆にきにしてませんでした。
こんなのきにするのはアセンブラで書いた時だけど、x86のアセンブラでさえ、
バイト列の連続rotateくらいしか書かなくなったんで…
Linux 2.4.18-powerpc (Debian woody 3.0)のgcc 2.95.4で試してみましたが、
「 2030405」を出力しました。
# 02030405にはならないですねえ。
Linux 2.4.24-sparc64-smpだとBus error。
nide@「ポィンタ」って表記も珍妙だな
In article <0502251322...@hayabusa.ics.nara-wu.ac.jp>, ni...@ics.nara-wu.ac.jp (NIDE Naoyuki) writes
> # 02030405にはならないですねえ。
%08x ですね。
> Linux 2.4.24-sparc64-smpだとBus error。
Bus error にするコードがわざわざ入っているってことなんでしょうね。
Register Window がらみかな?
Sparcでのアライメント違反はBus errorが「当然」ですよね。Solarisでもそ
うだし。Linux(のあるバージョン)ではSIGBUSはPOSIX.1ではないし、
Segmentation faultにリダイレクトされているのかと言う意味で
<squ8y5d...@stellar.co.jp>は書いたつもりなのです。
おお、家に帰ったらMacOS Xで試してみよう。
キャッシュが効くとか効かないとかが難しそう。絶対効かないアドレスにする
とSegmentation faultの方が出そうですね…
On Thu, 24 Feb 2005 14:53:09 +0000 (UTC), Shinji KONO <kono@ie.u-
ryukyu.ac.jp> wrote:
> 河野真治 @ 琉球大学情報工学です。
> In article <opsmnlzh...@news.media.kyoto-u.ac.jp>,
> 神戸隆行<ka...@nerimadors.or.jp> writes
>> Hoge* pHoge
>> と
>> int* pI
>> の間のキャスト
>> (Hoge*)pI
>> と
>> (int*)pHoge
>> はどちらもそれぞれがまともに初期化されていたとしても
>> 一般にまともな結果になりません。
>
> これは、思い違いじゃない? (void*)にキャストするってのは、割
> りとあるわけだし。
>
> あぁ、そうか。Hoge の最初のint member にアクセスするのに、pI
> にキャストしてもうまくいくとは限らないってことね。そういうア
> ーキテクチャってあるのかな?
まぁ、それはあるんですけれども…。
ポインタをアドレスを指すものと意味づければ殆どの場合に多分動くんですが…。
形式的な意味に従って型の違うポインタへのキャストは極力避けておいた方がいいかと。
構造体へのポインタと先頭のメンバへのポインタを不用意に混同してキャストして使ってると
なんといっても読み難いですし、
後で構造体のメンバを追加・変更したときに泣きを見ることになると思うので…。
#C++へ移行したときには仮想関数とか使った瞬間にイキナリ困りますし。
色々な型へのポインタを一つの関数・変数で受けなきゃいけなくてvoid*にする場合も
後で使うときには基本的に元の型に戻すでしょうし。
#イキナリ先頭メンバへのポインタに戻すんじゃなくて。
一群の構造体へのポインタ型でも型IDが入った共通部分があれば、
一気にvoid*まで落ちずに共用体とか使う手もありますし。
#C++なら継承を使うところですが。
On Fri, 25 Feb 2005 04:22:23 GMT
ni...@ics.nara-wu.ac.jp (NIDE Naoyuki) wrote:
> nide@「ポィンタ」って表記も珍妙だな
すみません。タイプミスです。
--
K.Moriyama
> > あぁ、そうか。Hoge の最初のint member にアクセスするのに、pI
> > にキャストしてもうまくいくとは限らないってことね。そういうア
> > ーキテクチャってあるのかな?
>
> まぁ、それはあるんですけれども…。
> ポインタをアドレスを指すものと意味づければ殆どの場合に多分動くんですが…。
>
> 形式的な意味に従って型の違うポインタへのキャストは極力避けておいた方がいいかと。
> 構造体へのポインタと先頭のメンバへのポインタを不用意に混同してキャストして使ってると
> なんといっても読み難いですし、
読み難いし、不用意にしない方がよいのは同意ですが、ちょっと language
lawyer っぽい小うるさいことをいわせていただくと、
6.7.2.1 Structure and union specifiers
... A pointer
to a structure object, suitably converted, points to its
initial member (or if that member is a bit-field, then to
the unit in which it resides), and vice versa. There may be
unnamed padding within a structure object, but not at its
beginning.
ですので、Cでは一応どの環境でも動きます。
(まあ、普通は、
&(struct_ptr->initial_member)
と書くだろうとは思いますが。)
前田敦司
みなさん、どうもありがとうございました。
おかげでエラー無しでコンパイル出来るようになりました。
On Thu, 24 Feb 2005 14:47:23 +0000 (UTC)
ko...@ie.u-ryukyu.ac.jp (Shinji KONO) wrote:
> > static struct tGroupName {
> > int iDummy ;
> > int iDummy2 ;
> > } ; < ここに名前が無いのは変なのですが、
> > メーカ説明では、何も記載されて
> > いません。
>
> 構造体の宣言なので、特に変ではないです。でも、このstatic
> は無意味だと思う。
ご指摘の通りで、私の間違いでした。又、マニュアルを確認した
所、static の記述は有りませんでた。尚、これ以外の部分は記述
通りです。
On Thu, 24 Feb 2005 23:28:47 +0900
齊藤 敦志 <sa...@s4.xrea.com> wrote:
> そういうことであれば、単に
>
> int biSetPointer (tSample **piTemp)
> {
> *piTemp = pgSystem;
> return 1;
> }
>
> という感じでいいんではないかと。
On Thu, 24 Feb 2005 14:47:23 +0000 (UTC)
ko...@ie.u-ryukyu.ac.jp (Shinji KONO) wrote:
> static struct tGroupName sUser ;
>
> void functionName ( struct tGroupName **pgUser )
> {
> *pgUser = &sUser;
> }
>
> とか。あるいは、free するルーチンを使って、
>
> void openGroupName ( struct tGroupName **pgUser )
> {
> *pgUser = (struct tGroupName *)malloc(sizeof(struct tGroupName *)) ;
> }
>
> void closeGroupName ( struct tGroupName **pgUser )
> {
> free(*pgUser);
> }
>
> みたいな。** が理解できるかどうかが問題ですけど...
上記を参考にして、コンパイルするとエラーが出なくなりました。
ありがとうございました。
# しかし、この[ ** ] が、手持ちのC言語関連書籍に見当たらない...
# 索引に無いだけで、どこかに書いてあるのかな?
> 僕は、struct は、typedef と必ず併用しろって教えてます。
>
> typedef struct tGroupName {
> int iDummy ;
> int iDummy2 ;
> } TGROUPNAME, *TGROUPNAME_PTR;
>
> としてやれば、
>
> static TGROUPNAME sUser ;
>
> void functionName ( TGROUPNAME_PTR *pgUser )
> {
> *pgUser = &sUser;
> }
>
> ってな感じ。** 使えない人には便利?
やはりそうですか、書籍等の説明を読んだ感じでは、typedef を
使用した方がスッキリするな~という印象を持ったので...
--
K.Moriyama
On Fri, 25 Feb 2005 22:22:44 +0900, K.Moriyama <for...@ma.kcom.ne.jp>
wrote:
> # しかし、この[ ** ] が、手持ちのC言語関連書籍に見当たらない...
> # 索引に無いだけで、どこかに書いてあるのかな?
**x = *(*x)
です。
型の方は
typedef X* PX;
とすると
PX*型とX**型が同じです。
On Fri, 25 Feb 2005 22:22:44 +0900
"K.Moriyama" <for...@ma.kcom.ne.jp> wrote:
> # しかし、この[ ** ] が、手持ちのC言語関連書籍に見当たらない...
[ ** ]という物が有るのでなくて、単項演算子としての[ * ] の
二重使用のようですね...うーん何かややこしい...
--
K.Moriyama
投稿がすれ違ったようです。神戸さん、わざわざありがとうございます。
On Fri, 25 Feb 2005 22:53:33 +0900
神戸隆行 <ka...@nerimadors.or.jp> wrote:
> **x = *(*x)
>
> です。
>
> 型の方は
> typedef X* PX;
> とすると
> PX*型とX**型が同じです。
ああ、そうゆう事なのですね。しかしややこしい、なれの問題かな~
--
K.Moriyama
この「ややこしい」が意味のことなら,関数のネストと同程度のややこしさだと
思います.#関数だと ( ) が要るから * より面倒とも言える.
また,記法に関することなら,C以前は,
int **x;
の様な書き方が「発明」されていなかったため,ポインタ絡みの宣言はとてもと
ても面倒でした.感じとしては,
variable x is pointer of pointer of integer
みたいな.
#Cには pointer に相当するキーワードが無い(要らない)ことに注意.
#Dereference 演算子というのは凄い「発明」なんですよ~~.
--
Hideki Kato <mailto:ka...@pop12.odn.ne.jp>
In article <421fdd27.7071%ka...@pop12.odn.ne.jp>, Hideki Kato <ka...@pop12.odn.ne.jp> writes
> また,記法に関することなら,C以前は,
> int **x;
> の様な書き方が「発明」されていなかったため,ポインタ絡みの宣言はとてもと
> ても面倒でした.感じとしては,
> variable x is pointer of pointer of integer
> みたいな.
ここら辺、もう諦めてて、わからん人にはわからんのだとか思ってます。
先生なのにそれでいいのかぁ~
茶々ですいません。
variable x is pointer to pointer to integer
では?
--
******************************
keizi kounoike
******************************
> また,記法に関することなら,C以前は,
> int **x;
> の様な書き方が「発明」されていなかったため,ポインタ絡みの宣言
> はとてもとても面倒でした.感じとしては,
それは違うでしょ。Cの「宣言子」はすごく分かりづらい、悪しき発
明です。それはたぶん言語屋すべての共通認識でしょう。Algol68とかは
var x: ref ref int;
とかこんな感じだったかな。これで十分分かりやすいですよ。これはC
より古いよね。Cと同世代っていうとPascalだけど
var x: ↑↑integer;
これも一層簡潔でいいじゃないですか。ひきかえCは変数名の側にいろ
いろくっつけるから込み入ったものになると読めたもんじゃない。
> variable x is pointer of pointer of integer
わざとそういう長ったらしい書き方を発明して煽るのはちょっと…
> #Dereference 演算子というのは凄い「発明」なんですよ~~.
で、その演算子はCが最初じゃないってのもご存知ですよね 久野
In article <cvosgq$b...@utogw.gssm.otsuka.tsukuba.ac.jp>, ku...@gssm.otsuka.tsukuba.ac.jp wrote:
>久野です。
>
>ka...@pop12.odn.ne.jpさん:
>> また,記法に関することなら,C以前は,
>> int **x;
>> の様な書き方が「発明」されていなかったため,ポインタ絡みの宣言
>> はとてもとても面倒でした.感じとしては,
>
> それは違うでしょ。Cの「宣言子」はすごく分かりづらい、悪しき発
>明です。それはたぶん言語屋すべての共通認識でしょう。Algol68とかは
>
> var x: ref ref int;
>
>とかこんな感じだったかな。これで十分分かりやすいですよ。これはC
>より古いよね。Cと同世代っていうとPascalだけど
>
> var x: ↑↑integer;
>
>これも一層簡潔でいいじゃないですか。ひきかえCは変数名の側にいろ
>いろくっつけるから込み入ったものになると読めたもんじゃない。
この記法でキャストが書けますか? Cではここら辺が一貫してるから(何と
か :-)読めるんで,Cで読めたもんじゃないほど込み入ったものは,それが本
当に(意味的に)込み入ってるからだと思います.
#それを他の言語の記法で書いたら,もっと読みにくくなりませんか?
##宣言部と式中とで同じ形で書けるのは良い事だと思いますが...少なくと
##も,私にとっては目から鱗でした.
>> variable x is pointer of pointer of integer
>
>わざとそういう長ったらしい書き方を発明して煽るのはちょっと…
ここを読んでる人が Algol や Pascal の記法を知っているとは限らないで
しょ.だから「感じ」と断ってるわけで.
#煽ってるのは久野さんの方では?
ついでに,
In article <cvourb$5b0$1...@caraway.media.kyoto-u.ac.jp>, <koun...@mbh.nifty.com> wrote:
>茶々ですいません。
>
>variable x is pointer to pointer to integer
>
>では?
あぁ,自然言語だとそうなるかも知れませんねぇ(どうせなら不定冠詞も欲しい
が).でも,私の感覚だと,型宣言では of を使いたいなぁ,う~む.
>> #Dereference 演算子というのは凄い「発明」なんですよ~~.
>
> で、その演算子はCが最初じゃないってのもご存知ですよね 久野
Cが最初だと書いてますか?
#何を怒っているのかがわからん(真面.
--
Hideki Kato <mailto:ka...@pop12.odn.ne.jp>
----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
# 以下は、あくまでも初心者レベルの人間の戯言で、あまり目くじらを
# 立てずに、読んでください。
[ ややこしい ]というのは、表現としては不適切だったように思います。
むしろ、[ 不自然な感じ ] 又は [ 自然な思考に合わない ]という方が
より近いかもしれません。(あくまでもより近い感じという意味です。)
On Sat, 26 Feb 2005 11:21:27 +0900
Hideki Kato <ka...@pop12.odn.ne.jp> wrote:
> この「ややこしい」が意味のことなら,関数のネストと同程度のややこしさだと
> 思います.#関数だと ( ) が要るから * より面倒とも言える.
関数のネストをややこしいと思った事は有りませんし、 * の方が
面倒かと...
On 26 Feb 2005 04:04:42 GMT
ku...@gssm.otsuka.tsukuba.ac.jp wrote:
> それは違うでしょ。Cの「宣言子」はすごく分かりづらい、悪しき発
> 明です。それはたぶん言語屋すべての共通認識でしょう。Algol68とかは
ああ、そうなんです。すごく分かりづらいのです。C を使用してみた感想は
省メモリ・高速化 + 省キー入力という感じです。その為、可視性(可読性?)が
犠牲になっているという印象で、バグの発生しにくい構造にするという発想も
あまり無いように感じられます。特に関数から値を返す方法がポインタしか無い
というのはいただけません。まあ結局は、なれの問題なのでしょうが...
# 代入が [ = ]で、比較が [ == ]となっているのは、省キー入力ですよね。
# 又、D言語ではポインタを使用せずに値を返せるようになっていたかと...
> var x: ref ref int;
> var x: ↑↑integer;
確かにこれだと少しは分かりやすいですね、特に ref rer int は明確ですね。
# ところで、[ ↑ ]は[ ^ ]の事ですよね?
--
K.Moriyama
> 確かにこれだと少しは分かりやすいですね、特に ref rer int は明確ですね。
と思います。
> # ところで、[ ↑ ]は[ ^ ]の事ですよね?
Pascal User Manual and Reportでは「↑」だったように記憶してま
す。まあどっちでも分かればいいんですが。
EBCDICなマシンでは「^」もないんで@だったりして。 久野
ka...@pop12.odn.ne.jpさん:
> この記法でキャストが書けますか?
え、型名が書ければ書けるんじゃないの。Cみたいに書くなら「(↑↑
int)(x)」とか書けばいいと思いますが。Cのキャストもヒドイ機能かつ
ヒドイ記法だと思っていますけどね。
> Cではここら辺が一貫してるから(何とか :-)読めるんで,Cで読
> めたもんじゃないほど込み入ったものは,それが本当に(意味的に)
> 込み入ってるからだと思います.
一貫してますかねえ…それは主観の相違ですが。
> Cが最初だと書いてますか?
それはどうも。Cがスバラシイ発明をしたという主旨に読めたもので、
そういう主旨でないのなら異論はないのですが。
> #何を怒っているのかがわからん(真面.
いや別に怒ってはいないのですが。
Cがすばらしいとは思わないというだけでして。 久野
On Sat, 26 Feb 2005 20:53:16 +0900, K.Moriyama <for...@ma.kcom.ne.jp>
wrote:
> 森山です。
> 関数のネストをややこしいと思った事は有りませんし、 * の方が
> 面倒かと...
「慣れ」の部分を除いた場合、式そのものは
-x
という式が持つややこしさと大差はないと思います。
まぁ、単項演算子の-は型の変化は伴わない分だけは簡単ですが。
関数よりややこしい、つまり関数呼び出しの入れ子のほうが単純というのは
関数の入れ子は()による入れ子で目に見える形で
表されていることからくるのでしょう。
そこであるプログラムの流儀では括弧を多用することを勧めています。
**ppx=-**ppx*3;
じゃなくて
(*(*ppx)) = ((-(*(*ppx))) * 3);
と書けば誤解の余地がないってことですね。
#個人的にはやりすぎると却って読みにくい気もしないではないですが。
On Sat, 26 Feb 2005 21:49:54 +0900, 神戸隆行 <ka...@nerimadors.or.jp> wrote:
> 神戸です。
> **ppx=-**ppx*3;
> じゃなくて
> (*(*ppx)) = ((-(*(*ppx))) * 3);
自己応答しておきますが、上は()の付け方を示すためだけの人工的な例でして:
**ppx *= -3;
ないし
(*(*ppx)) *= -3;
と書けばええやんという話はあります。
On Sat, 26 Feb 2005 21:49:54 +0900
神戸隆行 <ka...@nerimadors.or.jp> wrote:
> 関数よりややこしい、つまり関数呼び出しの入れ子のほうが単純というのは
> 関数の入れ子は()による入れ子で目に見える形で
> 表されていることからくるのでしょう。
確かにそうですね。
> そこであるプログラムの流儀では括弧を多用することを勧めています。
>
> **ppx=-**ppx*3;
>
> じゃなくて
>
> (*(*ppx)) = ((-(*(*ppx))) * 3);
>
> と書けば誤解の余地がないってことですね。
( ) を使うことで分かりやすくなりますし、誤解によるミスが減り
そうですね。勉強になりました。
> #個人的にはやりすぎると却って読みにくい気もしないではないですが。
ケースバイケースと言うことで...
神戸さん、どうもありがとうございます。
--
K.Moriyama
On 26 Feb 2005 11:57:04 GMT
ku...@gssm.otsuka.tsukuba.ac.jp wrote:
> > # ところで、[ ↑ ]は[ ^ ]の事ですよね?
>
> Pascal User Manual and Reportでは「↑」だったように記憶してま
> す。まあどっちでも分かればいいんですが。
>
> EBCDICなマシンでは「^」もないんで@だったりして。 久野
そうか~、[↑]を使用しているのも有ったんだ...てっきり[ ^ ]だと
見辛いので強調しているのかと思いました。[ @ ]を使用しているのは
有りますね。しかし、[ ^ ]が無いマシンが有るとは知りませんでした。
--
K.Moriyama
私はほとんどをCで書いてきたのでそれに慣れきっているというのもありますが、
ダラダラと遠まわしな宣言を重ねるよりは、
少々記号的でも全体を見渡しやすい方がいいと思ってます。
ただ、心情としては中立派です。
言語を比較するときに機能の量は必ずしも優秀性を表さないと思います。
あえて限定された用途に特化することだってあるでしょう。
そもそもCがシステム記述用に作られたという経緯を考えれば、
アクロバティックなメモリアクセスが出来るということは至極当然です。
「出来てしまう」というデメリットはどうやっても避けれないですよ。
> 特に関数から値を返す方法がポインタしか無い
> というのはいただけません。まあ結局は、なれの問題なのでしょうが...
これも考え方の問題で、できるだけモジュールの中で処理を完結させる
というモジュールの独立性を意識すればこそとも取れます。
事実、UNIX等のCで書かれたシステムでは「ハンドル」といった
抽象的概念でリソースをコントロールすることが一般的ではないですか。
Cは「高級アセンブラ」と呼ばれることもありますが、
まさにその感覚で使えばぜんぜん違和感はありませんね。
ただ、折角の高級な部分は積極的に使いますけれども。
----
齊藤@生涯一趣味プロ
URI http://saito.s4.xrea.com/
e-mail sa...@s4.xrea.com
In article <cvpoec$p...@utogw.gssm.otsuka.tsukuba.ac.jp>, ku...@gssm.otsuka.tsukuba.ac.jp wrote:
>久野です。
> Cがすばらしいとは思わないというだけでして。 久野
う~んと,じっくり考えた結果,久野さんは
私の記事の意図を勘違いしてる
という結論に達しました.私の投稿は,Cの初心者の方の,
> [ ** ]という物が有るのでなくて、単項演算子としての[ * ] の
>二重使用のようですね...うーん何かややこしい...
この「ややこしい」という「感覚」を少しでも和らげようという意図/目的で書
いたもので,Cを礼賛するものではありません.
これは,他の言語,例えば Lisp を教える時に,"()" ばかりで云々と言う人
に対して,「begin, end と書く代わりに ( ) で済むと思えば,そう悪いもので
もないでしょ」と言うのと同じです.だからと言って,一般に,あるいは,常
に,begin, end より ( ) の方が優れていると言って/思っているわけではあり
ません.
プログラミング言語はその設計目的があって作られます.その目的を無視した比
較は,無意味とは言いませんが,生産的ではないと考えます.
Cの構文も,その設計目的※を考えれば,非常に優れたものであると考えます
が,それがプログラミングの初心者に向いているものであるとは「決して」思い
ません.
※使用者(プログラマ)のスキルも含む.
お分かり頂けたでしょうか?
> > [ ** ]という物が有るのでなくて、単項演算子としての[ * ] の
> >二重使用のようですね...うーん何かややこしい...
> この「ややこしい」という「感覚」を少しでも和らげようという意図
> /目的で書いたもので,Cを礼賛するものではありません.
ああ、なるほど、それは納得しました。
> Cの構文も,その設計目的※を考えれば,非常に優れたものであると
> 考えます
基本的にはそう思います。が、
> が,それがプログラミングの初心者に向いているものであるとは「決
> して」思いません.
宣言子の構文についていえば、初心者でなくても向いていない「失敗
作」だと思っています。※
> お分かり頂けたでしょうか?
はい、それは納得しました。
※の議論は興味があればやりましょう。 久野
> そうか~、[↑]を使用しているのも有ったんだ...てっきり[ ^ ]だと
> 見辛いので強調しているのかと思いました。[ @ ]を使用しているのは
> 有りますね。しかし、[ ^ ]が無いマシンが有るとは知りませんでした。
AlgolやPascalでは、「規格書や教科書で使う表記法」と「実際のコンピュー
タへの入力で使う表記法」がありました。
教科書用の表記法では予約語は太字で表し、ポインタの表記に↑、かけ算の記
号に×などの記号を使い、またコメントは{ ... }を使っていました。
なお、Pascalの後継であるModula-2やOberonでは、ポインタ型は
pointer to integer
とか、
pointer to pointer to TreeNode
のように書きます。
# これらに比べ、Cの宣言子はひどいと私も思います。
前田敦司
Pascalと混ざってますよ。
REF REF INT x; (または REF REF REF INT x = LOC REF REF INT;)
ですね(ボールドを大文字で表現)。Cでも型は必ずtypedefすることにして、
ref_ref_int x;
とか書けばいいのかもしれないけど、typedefの時に、
typedef int **ref_ref_int;
と書かないといけない。
--
tksotn
On 27 Feb 2005 22:06:48 +0900
MAEDA Atusi <maeda...@ialab.cs.tsukuba.ac.jp> wrote:
> > そうか~、[↑]を使用しているのも有ったんだ...てっきり[ ^ ]だと
> > 見辛いので強調しているのかと思いました。[ @ ]を使用しているのは
> > 有りますね。しかし、[ ^ ]が無いマシンが有るとは知りませんでした。
>
> AlgolやPascalでは、「規格書や教科書で使う表記法」と「実際のコンピュー
> タへの入力で使う表記法」がありました。
>
> 教科書用の表記法では予約語は太字で表し、ポインタの表記に↑、かけ算の記
> 号に×などの記号を使い、またコメントは{ ... }を使っていました。
ああ、そうゆう事なのですね。
> なお、Pascalの後継であるModula-2やOberonでは、ポインタ型は
> pointer to integer
> とか、
> pointer to pointer to TreeNode
> のように書きます。
確かにこれだと分かりやすいですね。とは言え、私ごときがブツブツ
言っても始まりませんので、加藤さんや齊藤さんがおっしゃるように
思考を建設的な方向に向けてみました。
で、& と * を アッセンブラで言うところの Push Pop に見立て、
& : ポインタとしての階層を1段深める
* : ポインタとしての階層を1段浅くする
という風にとらえて、変数名には宣言時に [ * ]を使用した数だけ
接頭辞としての [ p ]を追加してみる事としました。又、宣言する時に
[ * ] は変数側では無く、型名側に着けるようにしてみました。
こうすれば、先のプログラムで呼び出し側の
biDone = biSetPointer ( &pgUser ) ;
の & は、ポインタとしての階層を1段深めるわけですから
この状態の変数は、 ppgUser と仮定出来るので、受けての関数
側で用意する変数の接頭辞は、ppgXXXX というようになる事がすぐに
判明します。この為、宣言するべき型名は tSample** となる事になる
ので、
int biSetPointer ( struct tSample** ppgTemp )
と、簡単に導き出せます。又 ppgTemp に pgSystem の ポインタを
設定するには、両者の階層を同じにする、つまり ppTemp の p を
取って pTemp にすれば良いので、ppgTemp に * を付けて *ppgTemp と
すれば * と 最初の p が相殺されて pgTemp となり、 pgSystem と
同等となりますから、
*ppgTemp = pgSystem ;
と成る事も、すぐに分かります。
この考えだと、例えば以下のように宣言した場合は
int* piDummy ;
piDummy : * も & も無くて接頭時の p が有るので、
データを指し示すアドレスとしてのポインタ。
*piDummy : * と p が 互いに相殺されるので iDummy 相当
となり、データとしての整数の値を示す。
&piDummy : & が有るので ppiDummy 相当となり ポインタの
有るアドレスを示す。
と考える事が出来るので、接頭時をうまく使用する事により、かなり
分かりやすくなるように思います。
で、最終的に例の動作確認用プログラムは以下のように
しました。
#include <stdio.h>
#define false 0
#define true 1
struct tSample {
int iDummy ;
int iDummy2 ;
} ;
static struct tSample gSystemArea ;
static struct tSample* pgSystem = & ( gSystemArea ) ;
int biSetPointer ( struct tSample** ppgTemp )
{
* ( ppgTemp ) = pgSystem ;
return ( true );
}
int main ( int srgc, char* argv[] )
{
static struct tSample* pgUser ;
int biDone ;
pgUser = ( struct tSample* ) malloc ( sizeof ( struct tSample ) ) ;
pgUser->iDummy = 15 ;
pgSystem->iDummy = 30 ;
pgUser->iDummy2 = 20 ;
pgSystem->iDummy2 = 40 ;
printf("pgUser->iDummy = %d\n" , pgUser->iDummy ) ;
printf("pgSystem->iDummy = %d\n" , pgSystem->iDummy ) ;
printf("pgUser->iDummy2 = %d\n" , pgUser->iDummy2 ) ;
printf("pgSystem->iDummy2 = %d\n" , pgSystem->iDummy2 ) ;
printf("pgUser = %d\n" , pgUser ) ;
printf("pgSystem = %d\n" , pgSystem ) ;
biDone = biSetPointer ( & ( pgUser ) ) ;
printf("pgUser->iDummy = %d\n" , pgUser->iDummy ) ;
printf("pgSystem->iDummy = %d\n" , pgSystem->iDummy ) ;
printf("pgUser->iDummy2 = %d\n" , pgUser->iDummy2 ) ;
printf("pgSystem->iDummy2 = %d\n" , pgSystem->iDummy2 ) ;
printf("pgUser = %d\n" , pgUser ) ;
printf("pgSystem = %d\n" , pgSystem ) ;
return ( 0 );
}
# ただこれだと、 宣言の int** は int&&の方がしっくりくるような...
まあ後は、ケースバイケースで、分かりやすい表記を考えてみたいと
思います。
--
K.Moriyama
> REF REF INT x; (または REF REF REF INT x = LOC REF REF INT;)
そうだったですか。
> ですね(ボールドを大文字で表現)。Cでも型は必ずtypedefすることにして、
そう、全部typedefしまくるというのが1つの手ですが、手間ですよね。
初期のCってtypedef無かったんですよね、たしか? 久野
何と何がイコールなのかという関係で考えると解りやすいかもしれません。
たとえば int **a; という文があった場合には、
森山さんは「a を int** とする」という風に捉えているのでしょう。
しかしながら*演算子は型名の一部というわけではないのです。
「**a が int であるとする」と考えれば何の不自然さもないと思います。
On Tue, 01 Mar 2005 21:44:23 +0900
齊藤 敦志 <sa...@s4.xrea.com> wrote:
> > # ただこれだと、 宣言の int** は int&&の方がしっくりくるような...
>
> 何と何がイコールなのかという関係で考えると解りやすいかもしれません。
> たとえば int **a; という文があった場合には、
> 森山さんは「a を int** とする」という風に捉えているのでしょう。
> しかしながら*演算子は型名の一部というわけではないのです。
> 「**a が int であるとする」と考えれば何の不自然さもないと思います。
どうもそのようですね、[ int** ppA ] は pp を ** で 相殺すると
[ int A ] となると考えれば、つじつまが合うようです。
取りあえずは、接頭辞をうまく使う事により、分かりやすいプログラムが
作成出来そうです。齊藤さん、重ね重ねの説明ありがとうございます。
--
K.Moriyama