ページ 1 / 1
どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月26日(月) 11:46
by 史上最悪のデスペナ
通信プログラムを組みたいのですが、
DXLibのサンプルを見ると文字列の例しか載っていません。
しかし、DXLibのサンプルを関数化して文字列に限らず引数に入れたデータを送受信できるようにしたいです。
なので
この関数にある
というのを用いればいいのではないかと思ったのですが
ためしに
コード:
void *A,*B,*C,*D;
int a=1;
float b=2.0;
char c='Null';
const char *d;
d = "NullNull";
A=&a;
B=&b;
C=&c;
D=&d;
としてみたのはいいのですが、ここ(A,B,C,D)からそれぞれの値を取り出すことが出来ません。
最終的に
コード:
DrawFormatstring(0,0,GetColor(255,255,255),"%d, %f, ?, ?",Aの中身,Bの中身,Cの中身,Dの中身)
とすると
1,2.0,Null,NullNull
と表示される様にしたいです
どうしたらいいか教えてください。(ちなみに?の部分は何をいれたらいいのか分からないのでそれも教えてください)
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月26日(月) 12:12
by softya(ソフト屋)
バイナリファイルを作る時と同じです。よく分からないならバイナリファイルから練習されては?
とりあえず構造体を引数にしてしまってポインタやクラスさえ含んでいなければちゃんと受け取れます。
ちなみに、構造体を使う場合はアライメント/パディングに気をつけてください。
「Visual C++でアラインメントを扱う3つの機能、#pragma pack, __declspec(align(#)), __alignof演算子についてのメモ 【▲→川俣晶の縁側→ソフトウェア→技術雑記】」
http://mag.autumn.org/Content.modf?id=20050430014843
それと
char c='Null';
と
d = "NullNull";
はNullと言う文字列にどういう意図が?
[補足]
ポインタ値を送信する事やバイナリファイルにすることは、ローカル変数のポインタを戻り値にするぐらいやってはいけないことです。
【追記】
受け取る側で何のデータがどの順番で何バイト続いているか把握する方法が必要なので、文字列が交じるデータの送信には工夫が必要です。
前の設定データの作り方の話でも出ていたち思いますが。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 11:46
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:バイナリファイルを作る時と同じです。よく分からないならバイナリファイルから練習されては?
とりあえず構造体を引数にしてしまってポインタやクラスさえ含んでいなければちゃんと受け取れます
一応はバイナリで保存は出来ます。
softya(ソフト屋) さんが書きました:それと
char c='Null';
と
d = "NullNull";
はNullと言う文字列にどういう意図が?
C言語のNULLとは関係ありません。別に、どんな文字列でもいいのですが私がMMOでよく使うキャラネームを入れただけです。
softya(ソフト屋) さんが書きました:ポインタ値を送信する事やバイナリファイルにすることは、ローカル変数のポインタを戻り値にするぐらいやってはいけないことです。
ポインタ値を送信する事やバイナリファイルにするのがいけないのは、ポインタがその変数が存在するメモリ上のアドレスのことだからそのときによって違うのでやっても無駄だということだと思いますが、「ローカル変数のポインタを戻り値にする」のがいけないのは何ででしょう?
[本文]
出来るだけ一般的な話にしようとすると話すのが下手なので誤解させてしまうようです・・・・・・・orz
簡単な例を挙げますと、(本家リファレンスより)
コード:
// 通信を確立
NetHandle = ConnectNetWork( Ip, 9850 ) ;
// 確立が成功した場合のみ中の処理をする
if( NetHandle != -1 ) NetWorkSend( NetHandle , "繋がったか~!?" , 17 ) ;
を関数化して
コード:
int connect( IPDATA IP, int Port, ?? Message)//注1
{
// 通信を確立
int NetHandle = ConnectNetWork( IP, Port ) ;
int Length = sizeof(Message);
// 確立が成功した場合のみ中の処理をする
if( NetHandle != -1 ) NetWorkSend( NetHandle , ?Message , Length ) ;//注2
return NetHandle;
}
//注1・・・・・??には型名が入ります。void *とか、charとか。
//注2・・・・・関数化しない場合は&が入りますが、この場合はどうすればいいのか・・・・・
[code]
として
[code]
IP.d1 = (中略)
int A = 1;
float B = 2.0;
string C = "史上最悪のデスペナ";
connect( IP, Port, A );
connect( IP, Port, B );
connect( IP, Port, C );
とすると相手側に「1」、「2.0」、「史上最悪のデスペナ」が送られるようにしたいです。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 12:43
by beatle
そういうことだったら、何でも保存できる変数の型を開発するより、関数のオーバーロードをしてはいかがでしょうか。
コード:
int connect(IPDATA ip, int port, int message);
int connect(IPDATA ip, int port, float message);
int connect(IPDATA ip, int port, const string& message);
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 12:46
by YuO
いくつか問題点がありますが……。
- データ長は外部から渡してもらうのがよいと思います。
template使えばsizeofを適用できなくもないですが,論理的なデータ長は物理的なデータ長とは別問題なので。
e.g.) charの配列に文字列が入っている場合,論理的なデータ長はsizeofではなくstrlenで取得する
- float型の値の実表現はint型等以上に実装依存です。
ISO 60559の32bit単精度浮動小数点数形式が多いとは思いますが,それに限るわけではありません。
int型ですら,実表現はある程度実装依存部分があります (負の数の表し方等)。
- バイトオーダーは実装依存です。
1 octetを超えるデータは,ビッグエンディアンかリトルエンディアンか,それともそれ以外の特殊なエンディアンか,といった情報の保持形式が異なる可能性があります。
送信側ではhtonsやhtonlを使ってエンディアンをビッグエンディアンに変換してネットワークを通し,受信側ではntohsやntohlを使ってエンディアンを元に戻す,という作業が必要です。
特定の環境専用で,クライアントも特定の環境のみというのであれば,後者2件はだいぶ緩和されますが……。
別スレッドである,
何処が悪いのか見ていただけますか?と合わせて考えるに,データの取り扱い方についての知識不足かな,という気がします。
史上最悪のデスペナ さんが書きました:一応はバイナリで保存は出来ます。
とはありますが,softya(ソフト屋)さんが言われていたのは,バイナリで保存できる,というレベルではなく,
可搬性のあるバイナリ形式を考えて構築することができるか,ということだと思います。
整数値ならば何octetあってどのエンディアンであるのか,
文字列ならば文字のエンコーディングは何で可変長か固定長か,可変長ならば長さはどういった方法で記録されているのか,
といったことを決めた(説明可能な)バイナリファイルは作成可能でしょうか。
基本的に,バイナリファイルへの入出力とネットワークへの入出力は同等とみなせます。
実際,Javaや.NETなどでは,どちらもストリームへの入出力として扱われます。
まぁ,ネットワークではいろいろ面倒なのでover HTTP(s)でJSONやXMLといった文字列にシリアライズすることも多いですが。
史上最悪のデスペナ さんが書きました:「ローカル変数のポインタを戻り値にする」のがいけないのは何ででしょう?
dangling pointerになるから。
コード:
void * get_pointer () {
int v = 0;
return &v;
}
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 12:56
by beatle
connect関数を単純にコピペして3つのオーバーロードされた関数を作ると、コードの重複がひどくなりますから、そこは工夫して下さい。たとえば、3つのオーバーロードされた関数ではmessageをvoid*に直す作業だけを行い、それ以外の共通の処理をまとめて一つの関数にします。
コード:
int connect(IPDATA ip, int port, const void* message, size_t n)
{
// 通信を確立
int net_handle = ConnectNetWork( ip, port ) ;
// 確立が成功した場合のみ中の処理をする
if( net_handle != -1 ) NetWorkSend( net_handle , message , n ) ;
return net_handle;
}
int connect(IPDATA ip, int port, int message)
{
connect(ip, port, &message, sizeof(message));
}
int connect(IPDATA ip, int port, float message)
{
connect(ip, port, &message, sizeof(message));
}
int connect(IPDATA ip, int port, const string& message)
{
connect(ip, port, message.c_str(), message.length());
}
YuOさんの指摘するバイトオーダーは、この実装では考慮されていませんので改良する必要があります。
とりあえずオーバーロードの考え方は分かっていただけると思います。
ちなみに、Boostにはany型という、何でも保存できる型があります。参考まで。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 14:01
by たかぎ
バイナリで送受信することが目的ではなく、あらゆる型のデータを送受信したいだけのようですから、いっそのこと次のようにしてはどうでしょうか?
コード:
template <class T>
int connect(IPDATA ip, int port, const T& message)
{
std::ostringstream oss;
oss << message;
std::string data(oss.str());
// 通信を確立
int net_handle = ConnectNetWork( ip, port ) ;
// 確立が成功した場合のみ中の処理をする
if( net_handle != -1 ) NetWorkSend( net_handle , data.c_str(), data.size() ) ;
return net_handle;
}
厳密にいえば、wchar_tやconst wchar_t*、std::wstringといったワイド文字系の型、あるいはchar16_tやchar32_tに関係する型に対応しなかったりしますが、まあいいでしょう。
(対応するのはそれほど難しくありません)
そういえば、volatile修飾された型にも対応していないので、どうしても必要ならremove_volatileした型でconst_castするなどしてください。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 16:03
by lriki
一見便利そうな関数ですけど、どんなふうに使うつもりなのかちょっと気になります。
サーバ・クライアント間のコネクション開始とか、ゲームとはあまり関係ないところに使うのであれば
それほど大きな問題は無いと思いますけど、ゲーム中にも使うとなるとちょっと疑問です。
というのも、NetWorkSend 関数は多分 TCP 使っていると思いますけど (DXライブラリには詳しくないので、的外れだったらごめんなさい)
int や float ひとつ毎に TCP 通信するのはちょっとやりすぎな気がします。
winsock で TCP 通信を行った場合、環境にもよりますけど1/60 秒に数回 send するだけで処理落ちしてしまいます。
(リアルタイムなゲームを作る場合だとちょっと致命的。スレッド使ったりすればある程度軽減できますが)
送信するデータはできるだけ構造体または配列にまとめて、送信回数をできるだけ少なくするように設計した方がいいですよ。
あと、たかぎさんの示してくれた例のように、データは文字列化して送受信した方が良いです。(シリアライズに多少時間がかかっても)
YuO さんの指摘のような環境毎の差を考慮する必要が殆ど無くなりますし、何よりデータが文字列なのでデバッグしやすくなります。
ちょっとおせっかいかもしれませんが、以下に以前に私が携わったネットワークゲームで使ったシステムのイメージを張っておきます。
さらっと書いただけなので多分バグあるかも。
あと、Name にスペース文字があると不具合が出ます(^^;
コード:
enum DataType
{
PLAYER_DATA = 1,
};
struct PlayerData
{
char Name[10];
int HP;
float X;
float Y;
/// 文字列化 (buf_ は十分に大きいこと)
void serialize( unsigned char* buf_ )
{
// buf_[0] はデータの種類を示すマジックナンバー
// buf_[1] は文字列部分のサイズ (最大 255)
// buf_[2] 以降に文字列データ
buf_[0] = PLAYER_DATA;
sprintf( &buf_[2], "%s %d %f %f", Name, HP, X, Y );
buf_[1] = strlen( &buf_[2] );
}
/// 復元 (buf_ には serialize() で文字列化されたものが入っている)
void deserialize( unsigned char* buf_ )
{
if ( buf_[0] == PLAYER_DATA )
{
sscanf( &buf_[1], "%s %d %f %f", &Name, &HP, &X, &Y );
}
else
{
// エラー
}
}
};
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 18:39
by 史上最悪のデスペナ
ネットで調べても表面上の意味しか分からない単語がずらずらと・・・・・・
ネットワークプログラミングが難しいと言われる理由を垣間見た気がします^^;
YuO さんが書きました:データの取り扱い方についての知識不足かな,という気がします。
自慢ではありませんが、データの取り扱いどころか一般人レベルに毛が生えた程度の孵化前のひよこであります!
beatle さんが書きました:YuOさんの指摘するバイトオーダーは、この実装では考慮されていませんので改良する必要があります。
エンディアンなるものは何かが分かりましたが、で?これをどう一致させるの?って感じです・・・・・・orz
たかぎ さんが書きました:wchar_tやconst wchar_t*、std::wstringといったワイド文字系の型、あるいはchar16_tやchar32_t
そんな型もあるんですね。知ってるのはint、float、double、char、string、void、const char *ぐらいですw
したがって
たかぎ さんが書きました:あらゆる型のデータを送受信したい
とはいってもint、float、string(もしくはchar)のみで十分だったりします
梨樹 さんが書きました:どんなふうに使うつもりなのかちょっと気になります。
今回挙げた例ではTCPを用いてますが、それはUDPでも送信データ部分は同じだと思ったからです。
スピード重視のデータはUDP、質重視のデータはTCPでもちろんやります。
具体的にはTCPはログインとかですね。UDPは戦闘の時とかゲームの根幹すべて。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月27日(火) 19:38
by softya(ソフト屋)
史上最悪のデスペナ さんが書きました:一応はバイナリで保存は出来ます。
これまでの話を総合すると出来ていないと思います。
特に文字列やクラスなどをバイナリ化する方法が分かっていませんよね。
だいぶ話が進んでいますが、やはり私はデータ確認が行い易いのでバイナリファイルで練習したほうが良いと思います。
練習のため条件として
・1回のデータは、fwrite一発で書き出すこと。そのために動的メモリ内で組み立ててから書きだすものとする。
・複数の可変文字列の混在データであること。
・今回の場合はエンディアンやオクテットはINTEL x86系に限定して良いと思います。
と言うことで、int、float、stringとcharが少なくともそれぞれ2回づつ以上で順番が混ざったものを書き出すプログラムを書いてみてください。doubleとかは良いのか気になりますが。
書き出しプログラムと書きだしたデータはバイナリエディタでちゃんと書けているか中身を確認してここに貼りつけてみてください。
[追記]
これが出来たら次は読みだすプログラムを作ります。
【追記の追記】
もしたかぎさんの提案されたテキスト送信方式にするなら全部のデータをテキスト化してファイルにするプログラムと元のデータに復号するプログラムを書いてみてください。ただし、fwrite一発で書きだす仕様は変更なしでお願いします。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月28日(水) 11:20
by 史上最悪のデスペナ
ごめんなさい。条件が理解できないので例を挙げていただいてもよろしいでしょうか?
softya(ソフト屋) さんが書きました:・動的メモリ内で組み立ててから書きだすものとする。
・複数の可変文字列の混在データであること。
私が思ったのは、数字や文字列を打ち込んでもらってそれを保存する
ということかと思ったのですがどうでしょう?
また、
softya(ソフト屋) さんが書きました:1回のデータは、fwrite一発で書き出すこと
というのは、構造体かなんかで
コード:
struct S_Test
{
中略
}
コード:
FILE *sf;
sf = fopen("data.Learn","wb");
fwrite( &S_Test, sizeof(S_Test), 1, sf);
fclose(sf);
とやるということでしょうか?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月28日(水) 12:00
by softya(ソフト屋)
>私が思ったのは、数字は勝手にプログラム内で固定するとして文字列は打ち込んでもらった文字列をcharやstring型として保存する
>ということかと思ったのですがどうでしょう?
charは文字列用ではありませんね。実の所、char c='null';と言うのはコンパイルできますが、値は一文字しか保存されません。試してみてください。
あとstring型は型ではなくクラスです。書き出すにはchar*型として取り出す必要があります。それとバイナリ化する場合は文字列長を何らかの形で保存しなくてはいけません。
史上最悪のデスペナ さんが書きました:また、
softya(ソフト屋) さんが書きました:1回のデータは、fwrite一発で書き出すこと
というのは、構造体かなんかで
それだけだと可変長の文字列データを上手く扱うことが出来ません。
よく使うのはVC++などの環境であれば
コード:
#pragma pack(push,1) //← 構造体アライメントを1バイトにしてパディングされないようにします。
typedef struct { //← C言語で互換性のある要素だけにして下さい。あえて文字列は考えたもらうために外してあります。
char c1;
int i1;
float f1;
int i2;
float f2;
char c2;
} binData_t;
#pragma pack(pop)
binData_t binData;
binData.c1 = 'c';
binData.c2 = 'd';
binData.i1 = 10;
binData.i2 = 100;
binData.f1 = 1.0f;
binData.f2 = 10.0f;
BYTE *binBuff = new BYTE[1024]; //← 本当は書きこむデータサイズをちゃんと確認して確保すべきです。
memcpy( binBuff, &binData, sizeof(binData) );
size_t size = sizeof(binData);
// 文字列の処理をします。
// 文字列を含めたバッファを全部書き出します。
fwrite( binBuff, size, 1, fp);
って感じでしょうか。コンパイルしましたがテストしてませんのでご了承ください。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月28日(水) 12:18
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:char c='null';と言うのはコンパイルできますが、値は一文字しか保存されません。試してみてください。
うろ覚えですが、charは文字列じゃなくて1文字が代入されるやつだから、char c[5]='null'ってすればいいんでしたっけ・・・・・?
コード:
#pragma pack(push,1) //← 構造体アライメントを1バイトにしてパディングされないようにします。
typedef struct { //← C言語で互換性のある要素だけにして下さい。あえて文字列は考えたもらうために外してあります。
char c1;
int i1;
float f1;
int i2;
float f2;
char c2;
} binData_t;
#pragma pack(pop)
が普通の構造体とどう違うのか(何となく動的メモリの確保だとかに関係してるのではないかと予想)
コード:
BYTE *binBuff = new BYTE[1024]; //← 本当は書きこむデータサイズをちゃんと確認して確保すべきです。
memcpy( binBuff, &binData, sizeof(binData) );
size_t size = sizeof(binData);
が何をしているのかが分からないので調べてきます。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月28日(水) 12:26
by softya(ソフト屋)
#pragma pack(push,1)はコンパイラに対する命令です。
次のようなことを理解すると良いと思います。
「データ型のアラインメントとは何か,なぜ必要なのか?」
http://www5d.biglobe.ne.jp/~noocyte/Pro ... nment.html
「C言語-ポインタとメモリと型(構造体)の関係 (2)」
http://www.mm2d.net/c/c-15.shtml
バイナリ関係を扱う以上は必須な知識ですのでよく勉強して下さい。
>うろ覚えですが、charは文字列じゃなくて1文字が代入されるやつだから、char c[5]='null'ってすればいいんでしたっけ・・・・・?
それだったら最初からstringクラスを使ったほうが良いでしょう。それとシングルクォートとダブルクォートの違いも勉強しましょう。
「データの扱い」
http://www9.plala.or.jp/sgwr-t/c/sec02.html
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月30日(金) 12:59
by 史上最悪のデスペナ
申し訳ありませんが、なかなか時間が取れないので続きは年明けになってしまいますが、来年もよろしくお願いします。
貼っていただいたリンク先の内容はちょっと難しかったです^^;
では、皆さん。良いお年をお迎えください
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月30日(金) 13:27
by softya(ソフト屋)
はい。時間が取れる時で良いですよ。
>貼っていただいたリンク先の内容はちょっと難しかったです^^;
解説はしますから聞いてくださいね。バイナリを作る以上は理解して欲しい事柄です。
セーブデータを作る時とか専用ツールを作る上では欠かせない知識ですから避けては通れませんよ。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月30日(金) 15:46
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:解説はしますから聞いてくださいね。バイナリを作る以上は理解して欲しい事柄です。
セーブデータを作る時とか専用ツールを作る上では欠かせない知識ですから避けては通れませんよ。
ありがとうございます。よろしくお願いします。
[追記]
今までバイナリでセーブできてると思ってたのは
構造体内が全部int型とfloat型で、しかも自分のPC内のみのスタンドアロンだからでしたorz
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2011年12月31日(土) 01:04
by softya(ソフト屋)
参考にバイナリ形式の有名ファイルフォーマット例を紹介します。
自分ならどうするか考えてみてください。
●構造体と可変長の組み合わせ
「bmp ファイルフォーマット」
http://www.kk.iij4u.or.jp/~kondo/bmp/index.html
●チャンク構造を持つファイルフォーマット
「wav ファイルフォーマット」
http://www.kk.iij4u.or.jp/~kondo/wave/
●シグネチャ方式。可変長のデータを含む
「ZIP (ファイルフォーマット) - Wikipedia」
http://ja.wikipedia.org/wiki/ZIP_(%E3%8 ... %E3%83%88)
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月01日(日) 13:27
by 史上最悪のデスペナ
明けましておめでとうございます。今年もよろしくお願いします。
このサイトの
5.2 複合データ型の各要素のオフセット
Di のアラインメントを Ai とすると, Addr(Di) は Ai の倍数である (アラインメントの定義).ここが分かりませんでした。
それと、文字列を含まないソフト屋さんのあげてくださった例をそのまま利用して
コード:
#include "DxLib.h"
#include "stdio.h"
#include "windows.h"
#include "string.h"
#pragma pack(push,1) //← 構造体アライメントを1バイトにしてパディングされないようにします。
struct binData_t{ //← C言語で互換性のある要素だけにして下さい。あえて文字列は考えたもらうために外してあります。
char c1;
int i1;
char str1[20];
float f1;
int i2;
float f2;
char str2[20];
char c2;
};
#pragma pack(pop)
binData_t binData;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
binData.c1 = 'c';
binData.c2 = 'd';
binData.i1 = 10;
binData.i2 = 100;
binData.f1 = 1.0f;
binData.f2 = 10.0f;
//BYTE *binBuff = new BYTE[1024]; //← 本当は書きこむデータサイズをちゃんと確認して確保すべきです。
size_t size = sizeof(binData);
//memcpy( binBuff, &binData, size );
// 文字列の処理をします。
FILE *sf;
sf = fopen("data0.ESO","wb");
// 文字列を含めたバッファを全部書き出します。
//fwrite( binBuff, size, 1, sf);
fwrite( &binData, size, 1, sf);
fclose(sf);
return 0;
}
としたところ、

- こうなりました.png (13.36 KiB) 閲覧数: 25539 回
上図のようになりました
0Aが10を、最初の64が100を16進数で表してるのは分かるのですが、float型はどうやってみればいいのでしょう?
また、ソフト屋さんの書いてくださったコードの一部(メモリーコピーのあたり)をコメントアウトしてみたのですが、コメントアウトする前とした後でバイナリデータに違いはありませんでした。何故するのか考えてみたのですが分からなかったので教えていただけますか?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月01日(日) 14:51
by YuO
アラインの問題は,元のページ以上に説明するのは難しそうなので省略。
# シリアライズに関していうならば,アラインではなくパディングの問題ではありますが。
史上最悪のデスペナ さんが書きました:loat型はどうやってみればいいのでしょう?
処理系不明ですが,DxLib 使うと言うことは Windows 上なのでおそらく float は IEEE 754 (ISO/IEC/IEEE 60559) の単精度 (binary 32) だと思います。
単精度の浮動小数点数は,1ビットの符号部,8ビットの指数部,23ビットの仮数部からなります。
# エンディアンを考慮した上で32ビット値として見た場合にこの順で並ぶ
詳しくは,Wikipedia の
単精度の項や
IEEE 754の項を参照して下さい。
なお,Cにおいてfloatの実装がIEEE 754に準拠する必要はありません。
そのため,ネットワークにおいて情報交換の為に使う場合は,プロトコルとしてIEEE 754で流すことを決めるか,
文字列等のプロトコル依存な交換形式に変換する必要があります。
史上最悪のデスペナ さんが書きました:また、ソフト屋さんの書いてくださったコードの一部(メモリーコピーのあたり)をコメントアウトしてみたのですが、コメントアウトする前とした後でバイナリデータに違いはありませんでした。何故するのか考えてみたのですが分からなかったので教えていただけますか?
memcpyもfwriteも指定したアドレスから指定されたサイズだけメモリをそのまま読み込みます。
元となるメモリの内容が同じですから,memcpyしたあとfwriteしようと,直接fwriteしようと結果は同じです。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月01日(日) 17:33
by softya(ソフト屋)
アドレスはアライメントで決まると言う事なので、アライメントが違うデータを構造体に並べてみれば分かると思います。その場合は#pragma pack(push,1)は外して下さい。
char,short,doubleなどなど。
史上最悪のデスペナ さんが書きました:また、ソフト屋さんの書いてくださったコードの一部(メモリーコピーのあたり)をコメントアウトしてみたのですが、コメントアウトする前とした後でバイナリデータに違いはありませんでした。何故するのか考えてみたのですが分からなかったので教えていただけますか?
あれは文字列を実装していないのでコピーしている意味はあまり無いです。文字列を実装してから意味を持ちます。
それとコピーしていなかったら値は不定だと思うのですが?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月02日(月) 12:49
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:あれは文字列を実装していないのでコピーしている意味はあまり無いです。文字列を実装してから意味を持ちます。
それとコピーしていなかったら値は不定だと思うのですが?
あれ・・・・・・・?違いがあるはずだと思って複数回やってみたのですが、毎回同じのが出力されました。
ちなみに、以下のように文字列を含んでても、コピーしようがしなかろうが結果が変わらなかったです。何故?
コード:
#include "DxLib.h"
#include "stdio.h"
#include "windows.h"
#include "string.h"
#pragma pack(push,1) //← 構造体アライメントを1バイトにしてパディングされないようにします。
struct binData_t{ //← C言語で互換性のある要素だけにして下さい。あえて文字列は考えたもらうために外してあります。
char c1;
int i1;
char str1[20];
float f1;
int i2;
float f2;
char c2;
char str2[20];
char str3[20];
};
#pragma pack(pop)
binData_t binData;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
binData.c1 = 'c';
binData.c2 = 'd';
binData.i1 = 10;
binData.i2 = 100;
binData.f1 = 1.0f;
binData.f2 = 10.0f;
strcpy( binData.str1, "史上最悪のデスペナ" );
strcpy( binData.str2, "ABCDEFGHIJK" );
//BYTE *binBuff = new BYTE[1024]; //← 本当は書きこむデータサイズをちゃんと確認して確保すべきです。
size_t size = sizeof(binData);
//memcpy( binBuff, &binData, size );
// 文字列の処理をします。
FILE *sf;
sf = fopen("data0.ESO","wb");
// 文字列を含めたバッファを全部書き出します。
//fwrite( binBuff, size, 1, sf);
fwrite( &binData, size, 1, sf);
fclose(sf);
return 0;
}
YuO さんが書きました:e.g.) charの配列に文字列が入っている場合,論理的なデータ長はsizeofではなくstrlenで取得する
このようにおっしゃってましたがどうすればいいか分からなかったのでひとまずsizeofでやりました。
すると、

- 出来てます?.png (15.65 KiB) 閲覧数: 25444 回
こんな感じになりました。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月03日(火) 20:18
by YuO
史上最悪のデスペナ さんが書きました:softya(ソフト屋) さんが書きました:あれは文字列を実装していないのでコピーしている意味はあまり無いです。文字列を実装してから意味を持ちます。
それとコピーしていなかったら値は不定だと思うのですが?
あれ・・・・・・・?違いがあるはずだと思って複数回やってみたのですが、毎回同じのが出力されました。
ちなみに、以下のように文字列を含んでても、コピーしようがしなかろうが結果が変わらなかったです。何故?
softya(ソフト屋)が言われている「文字列」はstd::stringのことだと思います。
単純にchar型の配列を構造体に用意したのであれば,問題は起きません。
これは,標準ライブラリのヘッダである<stdio.h>をインクルードしようとしているのでしょうか。
一応,プリプロセッサの#includeの規則上,"stdio.h"がインクルードできなければ<stdio.h>をインクルードするので問題は無いでしょうけれども,
標準ライブラリのヘッダは<>でインクルードするのがよいでしょう。
# 規格上は,<>付きでヘッダとして記述されています。
史上最悪のデスペナ さんが書きました:YuO さんが書きました:e.g.) charの配列に文字列が入っている場合,論理的なデータ長はsizeofではなくstrlenで取得する
このようにおっしゃってましたがどうすればいいか分からなかったのでひとまずsizeofでやりました。
文字列を書き出しているのではなく,構造体をファイルに書き出しているのですから,
今回の場合は論理的なデータ長は物理的なデータ長と一致し,sizeofで取得することが出来ます。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月04日(水) 00:21
by softya(ソフト屋)
史上最悪のデスペナ さんの方法だと半角で19文字を超えることは出来ませんし、これは固定長の方法で可変長ではありません。
softya(ソフト屋) さんが書きました:あれは文字列を実装していないのでコピーしている意味はあまり無いです。文字列を実装してから意味を持ちます。
それとコピーしていなかったら値は不定だと思うのですが?
これに関しては私のコードに対してコメントです。
史上最悪のデスペナ さんの方法は可変長文字列の実装とは言えません。と言うより単純に構造体で宣言することは絶対に出来ません。
パディングについても未検証のようなので気になるところです。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月05日(木) 13:24
by 史上最悪のデスペナ
全っ然分かりません・・・・・・・
文字列をバイナリ化(?)するを参考にしたら出来ますか?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月05日(木) 13:29
by softya(ソフト屋)
同じ事は、ここでも既に書かれている気がしますが何が分からないのでしょうか?
リンク先を参考にstringクラスの文字列をバイナリファイルとして書き出して見ましたか?
【追記】
もしC++が使えない状況で、C言語で可変長(最大値不明)、可変個数(最大値不明)の文字列一覧を扱う場合はどの様なデータ構造を使い管理しますか?まず、そこから考えてみるってのはどうでしょう。これを応用してポインタをファイル相対値に書き換えてファイルに書きだせばバイナリファイルになります。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月05日(木) 13:51
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:同じ事は、ここでも既に書かれている気がしますが何が分からないのでしょうか?
同じであるということすら分かりません・・・・・・・。
とりあえずstringに関して、こことリンク先から分かったことは
・stringは内部でポインタ型になっている
・構造体内にポインタあるとそれはバイナリとして保存されない。
ということだけです。
(かつて出てきたエンディアンとかoctetとかアライメントに関しては取り合えず無視)
梨樹 さんが書きました:
ちなみに、std::string は以下のようにすると保存できます。
コード:
std::string str( "ABC" );
// 書き込み
{
std::ofstream ofs( "test.dat", std::ios::binary | std::ios::trunc );
ofs << str << std::endl;
}
// 読み込み
{
std::ifstream ifs( "test.dat", std::ios::binary );
ifs >> str;
}
リンク先にはこのようにあるのでこれを使えばいいのかなという気がしますが
(ofs << str << std::endl;とか何をしてるのかさっぱり分からないけどコピペして自分の変数名に置き換えればいいのかな)、
でもそれをどうやってコピーしたメモリ内に割り込ませればいいのかとかがネットで調べてみたのですが全然分かりません。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月05日(木) 14:31
by softya(ソフト屋)
とりあえずstringクラスというのは忘れてC言語的な文字列で扱ってみましょう。
softya(ソフト屋) さんが書きました:【追記】
もしC++が使えない状況で、C言語で可変長(最大値不明)、可変個数(最大値不明)の文字列一覧を扱う場合はどの様なデータ構造を使い管理しますか?まず、そこから考えてみるってのはどうでしょう。これを応用してポインタをファイル相対値に書き換えてファイルに書きだせばバイナリファイルになります。
これをやって見ませんか?
史上最悪のデスペナ さんが書きました:(ofs << str << std::endl;とか何をしてるのかさっぱり分からないけどコピペして自分の変数名に置き換えればいいのかな)、
ofstreamクラス 自体の機能をご存知ですか?
調べないうちに触っても訳がわからないと思いますよ。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月05日(木) 14:50
by lriki
パディングとかエンディアンとかいろいろなものが出てきて
混乱してしまってるような気がします。
いずれはみんな必要になりますけど、今はちょっと置いておいて
まずは単純に可変長のデータを書き出すことだけに集中した方がいいんじゃないかと思います。
余裕がありましたら、以下の問題をどぞ。
コード:
#include <iostream>
#include <string>
#include <fstream>
void write( const char* str, float f )
{
printf( "\n入力されたデータ\nstr:%s\nf :%f\n", str, f );
// ▼ ここから下に、str と f を保存するプログラムを書いてみてください。
// ※ C の標準関数のみ使い、fwrite は 1 度だけ使う事。
// ▲ ここまで
}
int main()
{
std::string str;
float f;
std::cout << "文字列を入力:";
std::cin >> str;
std::cout << "実数を入力:";
std::cin >> f;
write( str.c_str(), f );
return 0;
}
あと、std::ifstream とかの C++ の入出力機能は慣れないと混乱するだけなので
今は使わない方がいいと思います。
std::string は c_str() でchar型の文字列を取り出せばfwrite で保存できますし。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月05日(木) 19:13
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:とりあえずstringクラスというのは忘れてC言語的な文字列で扱ってみましょう。
softya(ソフト屋) さんが書きました:
【追記】
もしC++が使えない状況で、C言語で可変長(最大値不明)、可変個数(最大値不明)の文字列一覧を扱う場合はどの様なデータ構造を使い管理しますか?まず、そこから考えてみるってのはどうでしょう。これを応用してポインタをファイル相対値に書き換えてファイルに書きだせばバイナリファイルになります。
これをやって見ませんか?
分かりました。梨樹さんの方が簡単だったらそっちを先にやるかもしれませんが・・・・・・
softya(ソフト屋) さんが書きました:ofstreamクラス 自体の機能をご存知ですか?
調べたら
ここが引っかかったのですが、このサイトは私には難しいようです。C言語に関して調べると大抵このサイトが引っかかるので良サイトなのは分かるのですが^^;
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月07日(土) 16:24
by 史上最悪のデスペナ
頑張ってみたのですがやはり分かりません。(ver.梨樹さん)
梨樹さんのプログラムをフルコピペするとWin16がどうこうみたいなよく分からないエラーになるので
勝手にこちらでDxLibを用いる方法にしました。また、入力形式にするのは面倒だったのでプログラム内で
勝手に文字列を宣言しました
コード:
#include "DxLib.h"
#include <iostream>
#include <string>
#include <fstream>
void write( const char* str, float f )
{
printf( "\n入力されたデータ\nstr:%s\nf :%f\n", str, f );
// ▼ ここから下に、str と f を保存するプログラムを書いてみてください。
// ※ C の標準関数のみ使い、fwrite は 1 度だけ使う事。
BYTE *binBuff = new BYTE[1024]; //← 本当は書きこむデータサイズをちゃんと確認して確保すべきです。
size_t StrLen = strlen(str);
size_t FSize = sizeof(f);
//memmove( binBuff, str, StrLen );・・・・・・・・・・・a1
//memmove( &binBuff[StrLen+1], &f, FSize );・・・a2
FILE *sf;
sf = fopen("data0.ESO","wb");
//fwrite( binBuff, sizeof(binBuff), 1, sf);・・・・・・a3
//fwrite(str,strlen(str),1,sf);・・・・・・・・・・・・・・・・・・b
//fwrite(&f,sizeof(f),1,sf);・・・・・・・・・・・・・・・・・・・・c
fclose(sf);
// ▲ ここまで
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
std::string str;
float f;
str = "くぁwせdrftgyふじこlp";
f=10.0f;
write( str.c_str(), f );
DxLib_End();
return 0;
}
以上のような形にしました。
結果、
コメントのbを有効にすると上段
コメントのcを有効にすると中段
コメントのa系列を有効にすると下段

- 分かりません.png (14.65 KiB) 閲覧数: 24340 回
となりました。aが間違っているんでしょうが、これ以上は分かりませんでした
また、a1とa3を有効にしても下段と同じになりました。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月07日(土) 16:50
by ISLe
a3のsizeof(binBuff)はポインタのサイズですよ。
バッファすべて書き出すのか、最低限のサイズを書き出すのか、方針を決めましょう。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月07日(土) 16:52
by softya(ソフト屋)
コード:
memmove( binBuff, str, StrLen );・・・・・・・・・・・a1
memmove( &binBuff[StrLen+1], &f, FSize );・・・a2
FILE *sf;
sf = fopen("data0.ESO","wb");
fwrite( binBuff, sizeof(binBuff), 1, sf);・・・・・・a3
このプログラムの問題点は、
・文字列のサイズをファイルに書き込んでいないこと。
・文字列終端を表すナル文字が書き出されていない事。
・binBuffと言うのはポインタなのでポインタのサイズをfrwriteしていること。
ですね。ここをまず直してみてください。
出来れば書き出すファイルフォーマットを先に決めて欲しいところです。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月07日(土) 22:46
by 史上最悪のデスペナ
出来ました!!!
コード:
// ▼ ここから下に、str と f を保存するプログラムを書いてみてください。
// ※ C の標準関数のみ使い、fwrite は 1 度だけ使う事。
BYTE *binBuff = new BYTE[1024]; //← 本当は書きこむデータサイズをちゃんと確認して確保すべきです。
size_t StrLen = strlen(str);
size_t FSize = sizeof(f);
size_t Total = StrLen + FSize + 3;
memmove( binBuff, &StrLen, 1);
memmove( &binBuff[1], str, StrLen );
memmove( &binBuff[StrLen+1], "\0", 2 );
memmove( &binBuff[StrLen+3], &f, FSize );
FILE *sf;
sf = fopen("data0.ESO","wb");
fwrite( binBuff, Total, 1, sf);
fclose(sf);
delete []binBuff;
// ▲ ここまで
結果がこちらです

- バグっているようです.png (7.13 KiB) 閲覧数: 24330 回
データの最初の「1E」は10進数の「30」であり、(1Eを消してみて分かりましたが)後ろは「くぁwせdrft」が入っているので文字列を入れれたことが分かりますが、最後の4つ「00 00 20 41」は、「10.0f」のみを保存したとき(「00 00 20 41」)と同じなので大丈夫だということが分かります。
softya(ソフト屋) さんが書きました:とりあえずstringクラスというのは忘れてC言語的な文字列で扱ってみましょう。
softya(ソフト屋) さんが書きました:
【追記】
もしC++が使えない状況で、C言語で可変長(最大値不明)、可変個数(最大値不明)の文字列一覧を扱う場合はどの様なデータ構造を使い管理しますか?まず、そこから考えてみるってのはどうでしょう。これを応用してポインタをファイル相対値に書き換えてファイルに書きだせばバイナリファイルになります。
これをやって見ませんか?
今度はこれをやってみたいと思います
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月07日(土) 23:34
by softya(ソフト屋)
2つの値の扱いが変です。
memmove( binBuff, &StrLen, 1);
これはコピーするStrLenのサイズを調べずに1バイトと決めつけています。256文字を超えたらどうしますか?
あとリトルエンディンだからたまたま上手く動いているだけです。
こっちは、ナル文字のバイト数が変です。
memmove( &binBuff[StrLen+1], "\0", 2 );
マルチバイト文字であればナル文字は1バイトです。
それとstrバッファにナル文字も入っているので、そのまま使いましょう。
惜しいところまでは来てるんですよ。
もうちょっとです。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 07:49
by 史上最悪のデスペナ
そんな・・・・・・・・・・・orz
softya(ソフト屋) さんが書きました:memmove( binBuff, &StrLen, 1);
これはコピーするStrLenのサイズを調べずに1バイトと決めつけています。256文字を超えたらどうしますか?
ここは
memmove( binBuff, &StrLen, sizeof(StrLen) );
とすればいいですよね。まあ、その後のmemmoveもそれに合わせて
&binBuff[sizeof(StrLen)],&binBuff[StrLen+sizeof(StrLen)]・・・・・としないといけませんが。
softya(ソフト屋) さんが書きました:あとリトルエンディンだからたまたま上手く動いているだけです。
リトルエンディアンは後ろから順に入っていくということしか分からないので今は
とりあえずパスします。させて下さい。
softya(ソフト屋) さんが書きました:マルチバイト文字であればナル文字は1バイトです。
¥0だから2文字だと思いました^^;
では、手直ししてきます。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 08:27
by 史上最悪のデスペナ
コード:
size_t StrLen = strlen(str);
size_t LenSize = sizeof(StrLen);
size_t FSize = sizeof(f);
size_t Total = StrLen + FSize + LenSize+1;
memmove( binBuff, &StrLen, LenSize);
memmove( &binBuff[LenSize], str, StrLen+1 );
memmove( &binBuff[StrLen+LenSize+1], &f, FSize );
バグっているようです.pngとほぼ同じですが、最初「1E」と「82」の間に「00 00 00」が入り、右側にちゃんと文字列の中身がフルで見えるようになりました。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 08:44
by beatle
史上最悪のデスペナ さんが書きました:¥0だから2文字だと思いました^^;
エスケープシーケンスというものを勉強してください.
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 08:51
by softya(ソフト屋)
うまくいきましたね。これでOKです。
次に取り掛かってみましょう。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 08:56
by 史上最悪のデスペナ
史上最悪のデスペナ さんが書きました:
softya(ソフト屋) さんが書きました:
とりあえずstringクラスというのは忘れてC言語的な文字列で扱ってみましょう。
softya(ソフト屋) さんが書きました:
【追記】
もしC++が使えない状況で、C言語で可変長(最大値不明)、可変個数(最大値不明)の文字列一覧を扱う場合はどの様なデータ構造を使い管理しますか?まず、そこから考えてみるってのはどうでしょう。これを応用してポインタをファイル相対値に書き換えてファイルに書きだせばバイナリファイルになります。
これをやって見ませんか?
次はこれですね
C++とCの違いからまずは調べてきます。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 12:59
by 史上最悪のデスペナ
可変個数(最大値不明)というのを満たしていませんが、
コード:
#include "DxLib.h"
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
#include <time.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
srand( time(NULL) );
int count = rand()%4;
int i;
char *Str[5];
Str[0] = "バイナリデータ作成練習";
Str[1] = "Let's make MMORPG!";
Str[2] = "そろそろネタがなくなってきたぞ";
Str[3] = "あと二つ・・・・何を書こうか";
Str[4] = "これで終わり";
size_t StrLen[5];
size_t LenSize[5];
for( i=0 ; i<5 ; i++ )
{
StrLen[i] = strlen( Str[i] );
LenSize[i] = sizeof( StrLen[i] );
}
size_t Total;
// ▼ ここから下に、str と f を保存するプログラムを書いてみてください。
// ※ C の標準関数のみ使い、fwrite は 1 度だけ使う事。
BYTE *binBuff = new BYTE[1024]; //← 本当は書きこむデータサイズをちゃんと確認して確保すべきです。
count++;
memmove( binBuff, &count, sizeof(count) );
Total = sizeof(count);
for( i=0 ; i<count ; i++ )
{
memmove( &binBuff[Total], &StrLen[i], LenSize[i] );
Total += LenSize[i];
}
for( i=0 ; i<count ; i++ )
{
memmove( &binBuff[Total], Str[i], StrLen[i]+1 );
Total += StrLen[i]+1;
}
FILE *sf;
sf = fopen("data0.ESO","wb");
fwrite( binBuff, Total, 1, sf);
fclose(sf);
delete []binBuff;
// ▲ ここまで
DxLib_End();
return 0;
}
としたところ

- 摩訶不思議.png (26.93 KiB) 閲覧数: 24310 回
となりました。
上下の違いは、バイナリデータ上のカーソル部です。(上は00あり、下は無し)
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 15:05
by softya(ソフト屋)
乱数で可変している意味があまり無いので5固定で良いと思います。
あとLenSize[]に入る値が全て固定なので、sizeof(size_t)で良いんじゃないでしょうか?
つまり、
memmove( &binBuff[Total], &StrLen, sizeof(size_t));
Total += sizeof(size_t);
の方がわかりやすいですし。
壊れているデータの方は原因がわかりません。
出力データを見るかぎり1バイト縮んだ事になりますがサイズ部分を見るかぎり同じデータなんですよね。これ再現性がありますか?
メモリ破壊要因がなくて時々データが破損すると言うことは、CPUかメモリが破損寸前ということも考えられます。
まぁ、普通パソコンが不安定になるはずなんですけどね。
で、少し問題があるかも知れないので読み込みを作ってみましょう。
私の趣味じゃないという所でもあるのですが。何処かは後で明かします。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 16:57
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:壊れているデータの方は原因がわかりません。
出力データを見るかぎり1バイト縮んだ事になりますがサイズ部分を見るかぎり同じデータなんですよね。これ再現性がありますか?
ごめんなさい。書き忘れてました。
上のは出力されたデータそのまま、下はこちらが勝手に00を消したものです。
乱数取得なので毎回データは変わりますが、同じ4個の文字列が書き出されたときは同じ状況が起きました。(3回のみ確認)
読み込みですね。分かりました。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 20:20
by 史上最悪のデスペナ
エラーの見方がわかりません。
コード:
#include "DxLib.h"
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
#include <time.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
ChangeWindowMode(TRUE);
DxLib_Init();
FILE *lf;
lf = fopen("data0.ESO","rb");
char *NumStr = "";
fgets( NumStr, sizeof(size_t), lf );
int Num = atoi( NumStr);
char *StrLen;
StrLen = new char[Num];
int i;
for( i=0 ; i<=Num ; i++ )
{
fgets( &StrLen[i], sizeof(size_t), lf );
}
char *Str;
Str = new char[Num];
for( i=0 ; i<=Num ; i++ )
{
fgets( &Str[i], StrLen[i]+1, lf );
}
delete []StrLen;
fclose(lf);
for( i=0 ; i<=Num ; i++ )
{
DrawFormatString( 0, 10*Num, GetColor(255,255,255), "%s", &Str[i] );
}
delete []Str;
DxLib_End();
return 0;
}
という読み込む(つもりで)コードを書いたのですが、
fgets( NumStr, sizeof(size_t), lf );で
SAO-Client.exe の 0x0132f77b でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x013b23d1 に書き込み中にアクセス違反が発生しました。
と出て、fgets.cの90行目 if ((*pointer++ = (_TSCHAR)ch) == _T('\n'))
に→が現れたのですが、どこを直せということでしょうか?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 21:20
by beatle
fgetsにNumStrを渡しているのがまずいんです.fgetsに渡すのは「バッファ」です.
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 21:22
by softya(ソフト屋)
バイナリデータですのでfgetsは相応しくないです。freadを使いましょう。fgetsは文字列専用です。
それとchar *NumStr = "";は書き換えできるメモリを確保しているわけではないので、エラーになります。
""は定数のポインタなのでNumStr が指す先は書き換えできませんし、型がcharである必要性もありません。
つまり、size_tの変数を定義してそこに読み込んだほうががシンプルなわけです。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 22:03
by 史上最悪のデスペナ
今度はこうなりました
コード:
#include "DxLib.h"
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
#include <time.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
ChangeWindowMode(TRUE);
DxLib_Init();
FILE *lf;
lf = fopen("data0.ESO","rb");
size_t Num;
fread( &Num, sizeof(size_t), 1, lf );
size_t *StrLen;
StrLen = new size_t[Num];
fread( StrLen, sizeof(size_t), Num, lf );
char *Str;
Str = new char[Num];
int i;
for( i=0 ; i<=Num ; i++ )
{
fread( &Str[i], StrLen[i]+1, 1, lf );
}
delete []StrLen;
fclose(lf);
for( i=0 ; i<=Num ; i++ )
{
DrawFormatString( 0, 10*i, GetColor(255,255,255), "%s", &Str[i] );
}
ScreenFlip();
WaitKey();
delete []Str;
DxLib_End();
return 0;
}
としたところ
Windows によって SAO-Client.exe でブレークポイントが発生しました。
ヒープが壊れていることが原因として考えられます。○○.exe または読み込まれた DLL にバグがあります。
あるいは、○○.exe がフォーカスを持っているときに、ユーザーが F12 キーを押したことが原因として考えられます。
可能であれば、出力ウィンドウに詳細な診断情報が表示されます。
だそうです。
場所はdelete []Str;でした
ちなみに、全く上手くいっておらず、こんな感じでした。

- これは・・・・.png (22.67 KiB) 閲覧数: 24280 回
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月08日(日) 22:24
by softya(ソフト屋)
char *Str;が間違っています。文字列を読み込むメモリが確保されていません。
Str = new char[Num];ではどう考えてメモリが足りませんよね?
必要なのは文字列の配列ですので、要はchar*の配列が必要になります。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 08:57
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:char *Str;が間違っています。文字列を読み込むメモリが確保されていません。
Str = new char[Num];ではどう考えてメモリが足りませんよね?
そんな単純なことを見落としていたとは・・・・・・・・・
ちなみに、プログラムの考え方自体は合っていますか?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 09:01
by softya(ソフト屋)
OKですよ。読み込む方法の一つとして合っています。
もう一つの方法は、最初にファイルサイズを調べて一括で読み込んでからバイナリの内容を取り出す方法です。newが一回で済むのでメモリ管理が楽です。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 11:53
by 史上最悪のデスペナ
史上最悪のデスペナ さんが書きました:
softya(ソフト屋) さんが書きました:char *Str;が間違っています。文字列を読み込むメモリが確保されていません。
Str = new char[Num];ではどう考えてメモリが足りませんよね?
そんな単純なことを見落としていたとは・・・・・・・・・
とはいうものの、どう直せばいいのかがわかりませんでした。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 12:00
by softya(ソフト屋)
要は文字列はchar型の配列なので、これを更に配列にする2次元配列になります。
ダブルポインタ**を使って下さい。
char **Str;
まず、ポインタであるchar*型をNumサイズ分確保して、つぎに各char*ごとに文字列を格納にするのに必要な大きさのメモリを確保してやります。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 12:33
by 史上最悪のデスペナ
コード:
char **Str;
*Str = new char[Num];
最初こうやったときにエラーになった(Strが初期化されてない)のは
softya(ソフト屋) さんが書きました:ポインタであるchar*型をNumサイズ分確保して、つぎに各char*ごとに文字列を格納にするのに必要な大きさのメモリを確保してやります。
をしてなかったからなんですね。
それを踏まえて
コード:
char **Str;
*Str = new char[Num];
int i;
for( i=0 ; i<=Num ; i++ )
{
Str[i] = new char[ StrLen[i]+1 ];
fread( &Str[i][i], StrLen[i]+1, 1, lf );
}
としてみたところ、
Run-Time Check Failure #3 - The variable 'Str' is being used without being initialized.
と出たのですが、「中断」ではなく「継続」させると以下のエラー文が出ました
○○.exe の 0x01242d9f でハンドルされていない例外が発生しました: 0xC0000005: 場所 0xcccccccc に書き込み中にアクセス違反が発生しました。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 13:20
by beatle
なんだか,史上最悪のデスペナさんの一連の書き込みを見ると,C言語のポインタや配列の知識がごっそり抜けているようですね.バイナリファイル云々という話をするまえに,ポインタ・配列・多次元配列あたりの勉強を,体系的におこなうのが良いと思います.
今のように,エラーが出たからその場所を直す,という場当たり的な学習では,きちんとしたまとまった知識は手に入りにくいと思います.
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 13:26
by 史上最悪のデスペナ
beatle さんが書きました:なんだか,史上最悪のデスペナさんの一連の書き込みを見ると,C言語のポインタや配列の知識がごっそり抜けているようですね.バイナリファイル云々という話をするまえに,ポインタ・配列・多次元配列あたりの勉強を,体系的におこなうのが良いと思います.
今のように,エラーが出たからその場所を直す,という場当たり的な学習では,きちんとしたまとまった知識は手に入りにくいと思います.
分かりました。取り合えず、勉強の旅に出かけてきます。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 19:31
by softya(ソフト屋)
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 19:41
by 史上最悪のデスペナ
調べても分かりませんと、泣きつこうと思ったら参考サイトを貼って下さっていたので
もう一度、流離ってきます
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 20:50
by 史上最悪のデスペナ
良く分かってないけど(ここ重要)一応出来ました。
コード:
char **Str = new char*[Num];
int i;
for( i=0 ; i<Num ; i++ )
{
Str[i] = new char[ StrLen[i]+1 ];
fread( Str[i], StrLen[i]+1, 1, lf );
}
分からない所は
コード:
//OK
char **Str = new char*[Num];
////////////////////////////////////////
//実行時エラー
char **Str;
**Str = new char*[Num];
である理由です。
まあ、全体的に消化しきれて無い感がありありですが追々勉強していけば何とかなるんじゃないかと希望的観測^^;
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 21:07
by softya(ソフト屋)
**Str と*StrとStrの違いを書いてみてください。
説明したサイトにも有ったと思いますが図を書いてみると理解が進むと思います。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 21:11
by 史上最悪のデスペナ
**Str・・・・・・・文字
*Str・・・・・・・・**Strのアドレス(メモリの番地)
Str・・・・・・・・・*Strのアドレス(メモリの番地が入っているメモリの番地)
かな?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 21:20
by softya(ソフト屋)
ちょっと微妙なのでcharを使って型で書いてみましょう。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 21:29
by 史上最悪のデスペナ
**Str・・・・・・char**
*Str・・・・・・・char*
Str・・・・・・・・char
のような気もするけど・・・・
**Str・・・・・・char***
*Str・・・・・・・char**
Str・・・・・・・・char*
ですかね?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 21:42
by beatle
史上最悪のデスペナ さんが書きました:**Str・・・・・・・文字
*Str・・・・・・・・**Strのアドレス(メモリの番地)
Str・・・・・・・・・*Strのアドレス(メモリの番地が入っているメモリの番地)
と
史上最悪のデスペナ さんが書きました:**Str・・・・・・char**
*Str・・・・・・・char*
Str・・・・・・・・char
が矛盾していることには気づいてますか?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 21:49
by 史上最悪のデスペナ
beatle さんが書きました:史上最悪のデスペナ さんが書きました:**Str・・・・・・・文字
*Str・・・・・・・・**Strのアドレス(メモリの番地)
Str・・・・・・・・・*Strのアドレス(メモリの番地が入っているメモリの番地)
と
史上最悪のデスペナ さんが書きました:**Str・・・・・・char**
*Str・・・・・・・char*
Str・・・・・・・・char
が矛盾していることには気づいてますか?
ほほう。そうなんですか。
じゃあ、
**Str・・・・・・・・・・char
*Str・・・・・・・・・・・char*
Str・・・・・・・・・・・・char**
かな?(消去法?勘?微妙な思い付きによる答え)
softya(ソフト屋) さんが書きました:説明したサイトにも有ったと思いますが図を書いてみると理解が進むと思います。
図が描けませんでした!
もう笑うしかないですね^^;全っ然理解できません。
なのに気付いたらランクが上級者にww
上級者以上のランカーで私以下のレベルの方がいるだろうか、いやいないだろう。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 21:56
by beatle
softyaさんは,charを使って「型で書け」と言ったのです.
C言語で1文字を表す型は char ですね.
C言語でcharへのポインタを表す型は char * ですね.
すなわち,C言語で「charへのポインタ」へのポインタを表す型は char ** です.
Strっていう変数名を使っていますけれど,Strはstringの略ですから,普通は文字列を表すのにstrという変数名を使います.
誤解の元ですから,char *以外の型の変数をstrという名前にするのは止めた方が賢明です.
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月09日(月) 22:04
by softya(ソフト屋)
ポインタは多くの人が躓くのでしっかり勉強しましょう。
まんまの「ポインタのポインタ」ってのが参考サイトにあるんですが読みましたか?
あと 単純なポインタから図を書いてみたほうが良いでしょうね。
ポインタだけで本があるぐらいですから理解を焦ってはダメですよ。
「Amazon.co.jp: ポインタ: 本」
http://www.amazon.co.jp/%E3%83%9D%E3%82 ... %BF&page=1
【補足】 参考を追加しておきます。自分が分かりやすいと思うものを読んでみてください。
「Part4 誰もがつまずくポインタを完璧理解 - C/C++は永久に不滅です!:ITpro」
http://itpro.nikkeibp.co.jp/article/COL ... 06/256198/
「C言語ポイント学習 (配列とポインタその1)」
http://www2.netf.org/pointer1.html
「第6回 ポインタを理解して文字列を扱う - よくわかるC言語:ITpro」
http://itpro.nikkeibp.co.jp/article/COL ... 31/252216/
「C言語~ポインタ~ -ヒバリのとまりぎ-」
http://spitzayano.web.fc2.com/arrangeme ... inter.html
それとデバッガを上手く使ってイメージを掴みましょう!ポインタや配列、文字列をデバッガで覗いてみましょう!
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 08:05
by 史上最悪のデスペナ
私が理解できないのがいけないのですが何か別の方向に向かっている気がするので
史上最悪のデスペナ さんが書きました:分からない所は
コード:
//OK
char **Str = new char*[Num];
////////////////////////////////////////
//実行時エラー
char **Str;
**Str = new char*[Num];
である理由です。
ここの部分を別にトピックを立てて、こっちでは(その場しのぎを繰り返しながら)次の段階にどんどん進めていっていただいても宜しいですか?
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 08:57
by Ryo
Strは「char**」型
それを使うときにも**をつけたら4つの*がついてることになる
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 09:07
by softya(ソフト屋)
セーブや通信を後回しにして別のことを並行するなら別に構わないと思いますが、セーブや通信をやるならポインタをまず理解しないと進まない状況だと思います。
[補足]ともかくトピックが長くなったので仕切り直すのは賛成です。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 10:10
by beatle
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 19:02
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:セーブや通信をやるならポインタをまず理解しないと進まない状況だと思います。
[補足]ともかくトピックが長くなったので仕切り直すのは賛成です。
エンディアンだとかバディングとかもポインタの知識が必要になりますか?メモリ関係なのでなりそうですが、あまり関係なかったら教えていただけると幸いです。
beatle さんが書きました:blog.php?u=783&b=2698
ポインタ攻略法を書いてみました.ご参考にどうぞ.
ありがとうございます。softya(ソフト屋)さんの貼ってくださったリンクと共に勉強させていただきます。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 19:09
by softya(ソフト屋)
史上最悪のデスペナ さんが書きました:エンディアンだとかバディングとかもポインタの知識が必要になりますか?メモリ関係なのでなりそうですが、あまり関係なかったら教えていただけると幸いです。
エンディアンは違うタイプのCPUが混ざらない限りは大丈夫です。ただ、バイナリエディタで見ているうちに覚える気もしますが。
パディングはメモリ配置の話ですので、バイナリデータで構造体を扱う限りは意識する必要があります。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 19:38
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:エンディアンは違うタイプのCPUが混ざらない限りは大丈夫です。
オンラインゲームを作りたいので知る必要がありますね。教えてください!
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 19:42
by softya(ソフト屋)
史上最悪のデスペナ さんが書きました:softya(ソフト屋) さんが書きました:エンディアンは違うタイプのCPUが混ざらない限りは大丈夫です。
オンラインゲームを作りたいので知る必要がありますね。教えてください!
とりあえず史上最悪のデスペナさんが使う可能性がある一般的パソコンで動いているWindows/Linux/MacはINTELやAMDのx86アーキテクチャを使っているので全部リトルエンディアンです。レンタルサーバーでこれ以外が無いわけはないですが、わざわざ借りることもないと思います。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 19:57
by 史上最悪のデスペナ
softya(ソフト屋) さんが書きました:とりあえず史上最悪のデスペナさんが使う可能性がある一般的パソコンで動いているWindows/Linux/MacはINTELやAMDのx86アーキテクチャを使っているので全部リトルエンディアンです。レンタルサーバーでこれ以外が無いわけはないですが、わざわざ借りることもないと思います。
じゃあもう全部リトルエンディアンでいいじゃん、と思ってしまいます^^;
では、ここは解決にしておきます。
ありがとうございました。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月10日(火) 20:46
by softya(ソフト屋)
あくまでも史上最悪のデスペナさんが使う環境の話ですのでゲーム機とかビックエンディアンのCPUは沢山あります。ファイル形式としてビックエンディンが定められているファイルもありますので、いつでもリトルエンディアンが通用するわけではありません。
Re: どんなデータ型(のアドレスでも可)でも保存できる変数ってありますか?
Posted: 2012年1月11日(水) 00:15
by ISLe
ネットワークバイトオーダーは一般的にビッグエンディアン…というのはここでは関係ない話ですね。
余談でした。