Re: 圧縮したい ( No.1 ) |
- 名前:管理人 日時:2017/09/05 01:17
> これと同じような使い方ができて書き込みの時に圧縮をかけて、読み込むときに解凍してくれる関数を作ることは可能でしょうか?
fwrite を実行すると自動的に圧縮される( 且つヘッダーは圧縮されない )といった関数の作成は
できないことはないかもしれませんが作るのは少し大変だと思います
圧縮するデータはあらかじめ malloc で確保したメモリ領域に memcpy などで書き込んでおいて、一括で圧縮をかけた後
fwrite でファイルに書き込むのが一番お手軽だと思います
FILE *fp;
errno_t err;
err = fopen_s(&fp, "SaveData\\data.sav", "wb"); //書き込みでファイルを開く fwrite(&fh, sizeof(file_header_t), 1, fp); //ファイルのヘッダ情報
fwrite(&fh, sizeof(file_header_t), 1, fp); //ファイルのヘッダ情報
unsigned char *buffer = malloc( 64 * 1024 * 1024 ); // 保存するデータより十分大きいメモリを確保
int size = 0;
// クリアフラグをメモリに書き込み
memcpy( buffer + size, &clear_f, sizeof(int) * 5 );
size += sizeof(int) * 5;
// ハッシュ値をメモリに書き込み
memcpy( buffer + size, &hash, sizeof(int) );
size += sizeof(int);
unsigned char *press_buffer = malloc( 64 * 1024 * 1024 ); // 圧縮データより十分大きいメモリを確保
int press_size;
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
buffer のデータを圧縮して press_buffer に格納、圧縮後のデータサイズを press_size に格納する処理
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
// 圧縮データのサイズを書き出し
fwrite(&press_size, sizeof(int), 1, fp);
// 圧縮データを書き出し
fwrite(press_buffer, press_size, 1, fp);
fclose(fp); //ファイルを閉じる
// 確保したメモリの解放
free( buffer );
free( press_buffer );
> zlibについていろいろ調べたのですが使い方が全く分かりませんでした。
zlibは圧縮ライブラリの中でも簡単な方だと思いますので、こちらが分からないと圧縮処理を行うのは難しいかもしれません
こちらのページ
<zlib の使い方 矢田 晋>
http://s-yata.jp/docs/zlib/
の、『一括圧縮・一括伸長』に書かれている compressBound, compress, uncompress の3つの関数を使用する方法が最も簡単だと思います
( 圧縮したいデータを malloc で確保したメモリに memcpy で書き込み → compress で圧縮 → fwrite で圧縮前のサイズの値と圧縮データをファイルに書き込み )
ただ、圧縮するデータが載せていただいたくらいのサイズ( int型変数 6個分 )だと、寧ろ圧縮後の方がデータサイズが大きくなってしまうかもしれません
|
Re: 圧縮したい ( No.2 ) |
- 名前:にこよん 日時:2017/09/05 23:30
> 圧縮するデータはあらかじめ malloc で確保したメモリ領域に memcpy などで書き込んでおいて、一括で圧縮をかけた後
> fwrite でファイルに書き込むのが一番お手軽だと思います
なんか少し前にそんな感じの記事見てあきらめた気がするのですがこれが一番簡単なんですか...
> <zlib の使い方 矢田 晋>
> の、『一括圧縮・一括伸長』に書かれている compressBound, compress, uncompress の3つの関数を使用する方法が最も簡単だと思います
ありがとうございます。読んでみます。
この流れで頑張ってみます。
> ただ、圧縮するデータが載せていただいたくらいのサイズ( int型変数 6個分 )だと、寧ろ圧縮後の方がデータサイズが大きくなってしまうかもしれません
サンプルで全てコピペすると邪魔かと思い一部省きました。
アイテムの情報(ほとんどが0の時が多い構造体)を大量に保存するので圧縮したいなと...
実際のサイズは12.4MBですが普通に圧縮すると30KBになるんですよね。
セーブスロットを100個用意しているので約1GBも消費してしまいます。
今週の土日ぐらいに再挑戦してみます。
|
Re: 圧縮したい ( No.3 ) |
- 名前:yumetodo 日時:2017/09/10 16:00
ちなみにzlib圧縮はboost.iostreamsを使うとかなり楽に圧縮解凍できたりするので、zlibをリンクしたboostを用意できるならそれを使う手もあります
|
Re: 圧縮したい ( No.4 ) |
- 名前:にこよん 日時:2017/09/28 04:17
> zlibをリンクしたboostを用意できるなら
少し調べてみたのですが、よく分からなかったので今回は普通に?やってみようと思います。
ありがとうございました。
|
Re: 管理人様 ( No.5 ) |
- 名前:にこよん 日時:2017/09/28 04:44
3週間もかかってしまいましたが、配列を圧縮してファイルに書き出し、
ファイルから読み込んだデータを展開して、違う配列に戻すことに成功しました。
まだゲームには組み込めていないのですが、多分もう大丈夫じゃないかなと思います。
ありがとうございました。
それと圧縮することには成功したのですが、いくつかわからないところがあります。
頂いたサンプルコードに書き足す形で圧縮してみたのですが、メモリの確保でエラーが出たのでキャスト?を付けました。
@それとZLibがBytef*型だったので↓の形に変えたのですが問題ないでしょうか?
m_buffer = (Bytef*)malloc(m_data_size * 2); //保存するデータより十分大きいメモリを確保
A十分大きなメモリというのはどうやって計算すればいいのでしょうか?
保存するデータの大きさは常に変わるので64 * 1024 * 1024←で固定するわけにはいかず、
とりあえず保存するデータのサイズを先に計算し、これを2倍したサイズ↓を確保しているのですが
保存するデータのサイズ + 128ぐらいのぎりぎりでも問題ないのでしょうか?
m_buffer = (Bytef*)malloc(m_data_size * 2); //保存するデータより十分大きいメモリを確保
BいまC++の勉強をしているのでこれらの処理を(初めて)クラスにまとめてみたのですが解凍したデータやファイルから
読み取ったデータが少し元のデータと違ったりします。
多分ポインタをあんまり理解しておらずエラーが出たら*や&を消したり書いたりしてるうちに完成したものだからだと思います。
お手数ですが下のコードで普通はしない(してはいけない)引数やクラス、ポインタの使い方があればご教授していただけないでしょうか?
#pragma comment(lib, "Zlib.lib") //Zlibをリンクする
#include <zlib.h> //Zlibをインクルードする
#include <stdio.h> //画面出力
#include <Windows.h>
#include <iostream> //C++の書き方
#include <string> //string型
#include <tchar.h> //_Tの定義
void Error(char * errorMessage, LPCTSTR lpszFuncName, int lineN)
{
char funcName[1024];
char message[1024];
sprintf_s(funcName, "%s(%04d)", lpszFuncName, lineN);
sprintf_s(message, "% -30s「%s」\n", funcName, errorMessage);
FILE *fp;
errno_t err;
err = fopen_s(&fp, "error.log", "a"); //書き込みでログファイルを開く
if (err != NULL) return; //ファイルを開いたときにエラーが返ってきたら戻る
fprintf_s(fp, message); //エラーメッセージを出力する
fclose(fp); //ファイルを閉じる
}
#define ERR(str) Error(str,_T(__FUNCTION__),__LINE__) //エラー時のマクロ
//データを圧縮してファイルに保存するクラス
class Save {
uLong m_data_size; //データのサイズ
uLong m_press_size; //圧縮後のデータのサイズ
Bytef *m_buffer; //データを保存するメモリのポインタ
Bytef *m_press_buffer; //圧縮データを保存するメモリのポインタ
public:
Save(int); //コンストラクタ
~Save(); //デトラクタ
Bytef* mem() const { return m_buffer; } //メモリのポインタを返す
void write(const char*,const char*, short int); //データを圧縮してファイルに書き込む
void read(char*, char*, short int*); //データをファイルから読み込んで展開する
};
Save::Save(int size) : m_data_size(size) { //コンストラクタ
m_buffer = (Bytef*)malloc(m_data_size * 2); //保存するデータより十分大きいメモリを確保
if (m_buffer == NULL) ERR("メモリの確保に失敗"); //エラーメッセージ
m_press_buffer = (Bytef*)malloc(m_data_size * 2); //圧縮後のデータより十分大きいメモリを確保
if (m_press_buffer == NULL) ERR("メモリの確保に失敗"); //エラーメッセージ
m_data_size = size; //データのサイズを保存
};
Save::~Save() { //デストラクタ
free(m_buffer); //確保したメモリの解放
free(m_press_buffer); //確保したメモリの開放
}
void Save::write(const char *path, const char *Identifier, short int Version) { //データを圧縮してファイルに書き込む
uLongf press_size;
if (compress2(m_press_buffer, &press_size, m_buffer, m_data_size, Z_BEST_COMPRESSION) != Z_OK) //データの圧縮
ERR("データの圧縮に失敗"); //エラーメッセージ
m_press_size = press_size; //圧縮後のサイズをコピー
char identifier[8]; //識別子の変数を定義する
for (int i = 0; i < 7; i++) identifier[i] = Identifier[i]; //ファイル識別子をコピーする
identifier[7] = '\n'; //終了文字を書き込む
FILE *fp;
errno_t err;
err = fopen_s(&fp, path, "wb"); //書き込みでファイルを開く
if (err != NULL) { //ファイルを開いたときにエラーが返ってきたら
ERR("セーブデータファイルの生成に失敗"); //エラーメッセージ
return; //戻る
}
fwrite(&identifier, sizeof(char), 8, fp); //識別子を書き込む
fwrite(&Version, sizeof(short int), 1, fp); //データのバージョン情報を書き込む
fwrite(&m_press_size, sizeof(uLong), 1, fp); //データのサイズを書き込む
fwrite(m_press_buffer, m_press_size, 1, fp); //圧縮データの書き出し
fclose(fp); //ファイルを閉じる
}
void Save::read(char *path, char *Identifier, short int *Version) {
FILE *fp;
errno_t err;
err = fopen_s(&fp, path, "rb"); //書き込みでファイルを開く
if (err != NULL) { //ファイルを開いたときにエラーが返ってきたら
ERR("セーブデータファイルの読み込みに失敗"); //エラーメッセージ
return; //戻る
}
fread(Identifier, sizeof(char), 8, fp); //識別子を読み込む
fread(Version, sizeof(short int), 1, fp); //データのバージョン情報を読み込む
fread(&m_press_size, sizeof(uLong), 1, fp); //データのサイズを読み込む
fread(m_press_buffer, m_press_size, 1, fp); //圧縮データを読み込む
fclose(fp); //ファイルを閉じる
if (uncompress(m_buffer, &m_data_size, m_press_buffer, m_press_size) != Z_OK) //データを展開
ERR("データの展開に失敗");
}
int main() {
int data1[40] = { 0,1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; //元データ
Save save(sizeof(int) * 40);
memcpy(save.mem(), data1, sizeof(int) * 40); //データをメモリにコピー
save.write("data1.sav", "nicoyon", 1); //圧縮してファイルに書き出す
static int data2[40]; //別の配列を定義する
for (int i = 0; i < 40; i++)
std::cout << data2[i]; //配列が0で埋められていることを確認
std::cout << std::endl;
Save load(sizeof(int) * 40);
short int a = 0;
char b[8];
load.read("data1.sav", b, &a); //識別子とデータファイルのバージョン情報を取得 + クラス内でデータの展開
memcpy(data2, load.mem(), sizeof(int) * 40); //メモリから配列にデータをコピー
for (int i = 0; i < 40; i++)
std::cout << data2[i]; //圧縮と展開に成功したか確認(元データに一致するか確認)
std::cout << std::endl << b << std::endl << a << std::endl << std::endl; //ファイル識別子とバージョン情報を確認
std::cout << std::endl << "全ての処理が完了しました" << std::endl<< "10秒後に終了します" << std::endl;
Sleep(10000);
ERR("強制終了");
return 0;
}
|
Re: 圧縮したい ( No.6 ) |
- 名前:管理人 日時:2017/09/30 01:15
> @それとZLibがBytef*型だったので↓の形に変えたのですが問題ないでしょうか?
> m_buffer = (Bytef*)malloc(m_data_size * 2); //保存するデータより十分大きいメモリを確保
はい、問題ありません
> A十分大きなメモリというのはどうやって計算すればいいのでしょうか?
> 保存するデータの大きさは常に変わるので64 * 1024 * 1024←で固定するわけにはいかず、
> とりあえず保存するデータのサイズを先に計算し、これを2倍したサイズ↓を確保しているのですが
> 保存するデータのサイズ + 128ぐらいのぎりぎりでも問題ないのでしょうか?
少し調べたところ、圧縮後のデータを格納するメモリ領域の適切なサイズは compressBound という関数で
取得することができるようです
なので、こちらの部分は
m_press_buffer = (Bytef*)malloc(m_data_size * 2); //圧縮後のデータより十分大きいメモリを確保
こうしていただければ良いと思います
m_press_buffer = (Bytef*)malloc(compressBound(m_data_size)); //圧縮後のデータより十分大きいメモリを確保
あと、圧縮元のデータを格納するメモリ領域は2倍のサイズにしなくても大丈夫です
> BいまC++の勉強をしているのでこれらの処理を(初めて)クラスにまとめてみたのですが解凍したデータやファイルから
> 読み取ったデータが少し元のデータと違ったりします。
載せていただいたコードを実行してみましたが、解凍したデータはちゃんと圧縮前のデータと一致していました…
> 多分ポインタをあんまり理解しておらずエラーが出たら*や&を消したり書いたりしてるうちに完成したものだからだと思います。
> お手数ですが下のコードで普通はしない(してはいけない)引数やクラス、ポインタの使い方があればご教授していただけないでしょうか?
少し拝見した限りでは著しく問題があるような箇所は見当たりませんでした
( identifier[7] = '\n'; の部分は、改行文字の '\n' ではなく終端文字の '\0' の方が適切ではないかな…と思った程度です )
|
Re: 圧縮したい ( No.7 ) |
- 名前:にこよん (解決) 日時:2017/09/30 15:43
> 少し調べたところ、圧縮後のデータを格納するメモリ領域の適切なサイズは compressBound という関数で
> 取得することができるようです
ありがとうございます。
調べ不足でした。すみません。
> あと、圧縮元のデータを格納するメモリ領域は2倍のサイズにしなくても大丈夫です
そうなんですか(;´・ω・)どれだけ確保すればいいかわからなかったもので...
普通に必要メモリだけ確保するようにしました。
> 載せていただいたコードを実行してみましたが、解凍したデータはちゃんと圧縮前のデータと一致していました…
データのサイズや型を変えるとなぜか0で埋まってたことがあったのですが、
今やってみるとなりませんでした。何かの書き間違えだったかもしれません。
> 少し拝見した限りでは著しく問題があるような箇所は見当たりませんでした
ご確認ありがとうございます。
とりあえずはこれを マイゲームライブラリ に追加して使っていこうと思います。
問題なく書けるように頑張ります!
> ( identifier[7] = '\n'; の部分は、改行文字の '\n' ではなく終端文字の '\0' の方が適切ではないかな…と思った程度です )
ほんとだ...気づきませんでした(;´・ω・)
実行結果のファイル識別子の後に半角カタカナの「フフフフフフフフフ」が入っていたのはこれが原因でしたか...
1時間ぐらい悩んだ末原因が分からなかったのでまぁいいかとあきらめていたのですが、こんな簡単なことだったとは。
助かりました。
わざわざ実行までしてくださって本当にありがとうございました。
だいぶ前からやってみたことがようやくできました。
かなり感動です(笑)
|
Re: 圧縮したい ( No.8 ) |
- 名前:にこよん 日時:2017/10/14 23:03
解決した!!....と思っていたのですが残念ながらエラーが出てしまいました。
debugでビルドした時は何の問題もないのですが、releaseでビルドした時にエラーが出てしまいました。
内容は Z_BUF_ERROR(メモリが足らない) でした。
これはメモリ確保にcompressBound()を使わずに元データと同じサイズ分のメモリを確保することで正常に動くようになったのですが、
友人にテストプレイしてもらったところ、また同じエラーが発生。
確保するメモリを2倍にしてもダメでした。
(メモリ確保に失敗したらエラーメッセージが返ってくるので本体のメモリ不足ではないかと思われます)
いろいろ調べたり試したりしてみたのですが全く動くようにならないので、推測できる原因などがあればご教示ください。
ソースコードはファイルの読み書きと同じように使えるように書き直したので貼りなおしておきます↓
//データを圧縮、展開してファイルに保存、読み込む
class Save {
uLong m_data_size; //データのサイズ
uLong m_press_size; //圧縮後のデータのサイズ
Bytef *m_buffer; //データを保存するメモリのポインタ
Bytef *m_press_buffer; //圧縮データを保存するメモリのポインタ
unsigned int m_write_size; //書き込み中のサイズ
public:
Save(int size); //コンストラクタ
~Save(); //デトラクタ
void wcpy(void const* Src, unsigned int Size); //保存するデータをメモリにコピーする
void rcpy(void *Src, unsigned int Size); //読み込んだデータをコピーする
int write(const char *path, const char *Identifier, short int Version); //データを圧縮してファイルに書き込む
int read(char *path, char *Identifier, short int *Version); //データをファイルから読み込んで展開する
};
Save::Save(int size) : m_data_size(size) { //コンストラクタ
m_buffer = (Bytef*)malloc(m_data_size); //保存するデータより十分大きいメモリを確保
if (!m_buffer) ERR("メモリの確保に失敗しました"); //エラーメッセージ
m_press_buffer = (Bytef*)malloc(compressBound(m_data_size)); //圧縮後のデータを保存するメモリを確保する
// m_press_buffer = (Bytef*)malloc(m_data_size); //圧縮後のデータを保存するメモリを確保する
if (!m_press_buffer) ERR("メモリの確保に失敗しました"); //エラーメッセージ
m_data_size = size; //データのサイズを保存
m_write_size = 0; //書き込み中サイズの初期化
};
Save::~Save() { //デストラクタ
free(m_buffer); //確保したメモリの解放
free(m_press_buffer); //確保したメモリの開放
}
void Save::wcpy(void const* Src, unsigned int Size) {
if (m_write_size >= m_data_size) { //保存データが確保したメモリのデータより大きかったら
ERR("保存するデータが大きすぎます"); //エラーメッセージ
return; //終了
}
memcpy(m_buffer + m_write_size, Src, Size); //データをメモリにコピーする
m_write_size += Size; //保存した分だけメモリを進める
}
void Save::rcpy(void *Src, unsigned int Size) {
if (m_write_size >= m_data_size) {
ERR("データサイズが確保分を超えました"); //エラーメッセージ
return; //戻る
}
memcpy(Src, m_buffer + m_write_size, Size); //メモリからデータをコピーする
m_write_size += Size; //保存した分だけメモリを進める
}
int Save::write(const char *path, const char *Identifier, short int Version) { //データを圧縮してファイルに書き込む
if (m_write_size != m_data_size) ERR("保存データのサイズが一致しませんでした"); //エラーメッセージ
uLongf press_size;
int z_err = compress2(m_press_buffer, &press_size, m_buffer, m_data_size, Z_BEST_COMPRESSION); //データの圧縮
if (z_err != Z_OK) { //エラーコードが返ってきたら
ERR("データの圧縮に失敗しました"); //エラーメッセージ
switch (z_err) {
case Z_MEM_ERROR:
ERR("Z_MEM_ERROR エラーが発生しました");
break;
case Z_BUF_ERROR:
ERR("Z_BUF_ERROR メモリに十分な空き容量がありません");
break;
case Z_STREAM_ERROR:
ERR("Z_STREAM_ERROR 圧縮レベルが不明です");
break;
default:
ERR("Z_ERROR 不明なエラーが発生しました");
break;
}
}
m_press_size = press_size; //圧縮後のサイズをコピー
char identifier[8]; //識別子の変数を定義する
for (int i = 0; i < 7; i++) identifier[i] = Identifier[i]; //ファイル識別子をコピーする
identifier[7] = '\0'; //終端文字を書き込む
FILE *fp;
errno_t err;
err = fopen_s(&fp, path, "wb"); //書き込みでファイルを開く
if (err != NULL) { //ファイルを開いたときにエラーが返ってきたら
ERR("セーブファイルの生成に失敗しました"); //エラーメッセージ
return 1; //戻る
}
fwrite(&identifier, sizeof(char), 8, fp); //識別子を書き込む
fwrite(&Version, sizeof(short int), 1, fp); //データのバージョン情報を書き込む
fwrite(&m_press_size, sizeof(uLong), 1, fp); //データのサイズを書き込む
fwrite(m_press_buffer, m_press_size, 1, fp); //圧縮データの書き出し
fclose(fp); //ファイルを閉じる
return 1;
}
int Save::read(char *path, char *Identifier, short int *Version) {
int dx_fp;
dx_fp = FileRead_open(path); //読み込みでファイルを開く
if (dx_fp == NULL) { //ファイルを開いたときにエラーが返ってきたら
ERR("セーブデータファイルの読み込みに失敗しました"); //エラーメッセージ
return 1; //戻る
}
FileRead_read(Identifier, sizeof(char) * 8, dx_fp); //識別子を読み込む
FileRead_read(Version, sizeof(short int), dx_fp); //データのバージョン情報を読み込む
FileRead_read(&m_press_size, sizeof(uLong), dx_fp); //データのサイズを読み込む
FileRead_read(m_press_buffer, m_press_size, dx_fp); //圧縮データを読み込む
FileRead_close(dx_fp); //ファイルを閉じる
if (uncompress(m_buffer, &m_data_size, m_press_buffer, m_press_size) != Z_OK) //データを展開
ERR("データの展開に失敗しました"); //エラーメッセージ
}
|
Re: 圧縮したい ( No.9 ) |
- 名前:管理人 日時:2017/10/15 15:48
> debugでビルドした時は何の問題もないのですが、releaseでビルドした時にエラーが出てしまいました。
> 内容は Z_BUF_ERROR(メモリが足らない) でした。
> これはメモリ確保にcompressBound()を使わずに元データと同じサイズ分のメモリを確保することで正常に動くようになったのですが、
こちらが気になります
compressBound で取得できるサイズは必ず元データのサイズより大きくなるはずなので、
『compressBound で取得できるサイズよりも小さい元データのサイズにしたら正常に動くようになった』
というのは少し変な気がします
手元でにこよんさんが載せてくださった No.8 の Saveクラスを No.5 のプログラムを使用して
releaseビルドで実行したところ、正常に動作しました
よろしければ『にこよんさんの環境でも releaseビルドだと Z_BUF_ERROR エラーが発生する』プログラムを
お書き込みいただけないでしょうか?
( にこよんさんの環境では正常に動いて、ご友人の環境ではエラーが発生するプログラムだと
私の環境でもエラーが発生しない可能性があるので… )
あと、No.5 のプログラムのように main関数も含まれた実際に実行できるプログラムにしていただけると検証しやすいです m(_ _)m
|
Re: 圧縮したい ( No.10 ) |
- 名前:にこよん 日時:2017/10/15 19:44
もう一人の友人(B)にもお願いしてcompressBoundを使わなかったほう(私の環境では正常に動くが友人Aの環境では動かなかったもの)
で実行してもらったのですが、正常に保存することができました
実際にエラーが出たのはゲームなので、保存する容量を全く同じ構造体にし、
同じような状況で保存するプロジェクトを作成してみたのですが、こちらはreleaseでもエラーは起こりませんでした
ゲーム内の別のプログラムに問題があるのかもしれません
debugとreleaseで変わるということはバッファオーバーラン?
もしそうなら、確保するメモリが小さくなることによって後で確保されるメモリがたまたまずれ、
重要でない領域がバッファオーバーランされるようになったと考えれば辻褄は合うでしょうか?
バッファオーバーランが起こった場合はメモリ不足のエラーが戻ってくるものなのでしょうか?
追記::
ただ、メモリを確保してから書き込むまでの間にゲームが介入できる場所はないんですよね...
実際にゲームで使用しているソースです↓
Save save(sizeof(save_data_t) + sizeof(int)*TEVENT_MAX + sizeof(enemy_t)*ENEMY_MAX + sizeof(item_t)*MAP_MAX * ITEM_MAX);
save.wcpy(&s_data, sizeof(save_data_t)); //ゲームデータの保存
save.wcpy(&event_flag, sizeof(int)*TEVENT_MAX); //イベントフラグの保存
save.wcpy(&s_enemy, sizeof(enemy_t)*ENEMY_MAX); //敵情報の保存
save.wcpy(&s_item, sizeof(item_t)*MAP_MAX * ITEM_MAX); //アイテム情報の保存
save.write(path, "nicoyon\0", 6); //ファイル識別子とバージョンを指定してファイルに書き込む
wcpyで渡したサイズの合計とコンストラクタに渡した初期のサイズの引数は全く同じでないとエラーが出るので、
サイズの書き間違えはないかと思います。
::
> よろしければ『にこよんさんの環境でも releaseビルドだと Z_BUF_ERROR エラーが発生する』プログラムを
> お書き込みいただけないでしょうか?
なので、少し難しいかもしれません
ゲームのプロジェクトを送ることならできそうです
環境↓
私→win10
友人A→不明(win7,8,10あたりだと思われる)
友人B→winXP
|
Re: 圧縮したい ( No.11 ) |
- 名前:管理人 日時:2017/10/15 20:35
> これはメモリ確保にcompressBound()を使わずに元データと同じサイズ分のメモリを確保することで正常に動くようになったのですが、
そういえば、『元データと同じサイズ分』ではなく『元データの2倍のサイズ分』にした場合もエラーは発生しますでしょうか?
> ゲーム内の別のプログラムに問題があるのかもしれません
> debugとreleaseで変わるということはバッファオーバーラン?
> もしそうなら、確保するメモリが小さくなることによって後で確保されるメモリがたまたまずれ、
> 重要でない領域がバッファオーバーランされるようになったと考えれば辻褄は合うでしょうか?
そうですね、最小のテスト環境での releaseビルドや debug ビルドではエラーが発生しないとなると
仰る通りゲーム内の別のプログラムに問題がある可能性は高いと思います
> バッファオーバーランが起こった場合はメモリ不足のエラーが戻ってくるものなのでしょうか?
バッファオーバーランによって不正なメモリ書き換えが行われてしまった後は
どのような動作も『不定』になりますので、何が起こってもおかしくありません
なので『必ずメモリ不足のエラーが戻ってくる』わけではありません、たまたま『メモリ不足のエラー』が
戻ってきているだけだと思います
なので、何か変更を加えて書き換わるメモリの位置が変化すると今度は別のエラーが戻ってきたり、
zlib 以外の処理の部分でエラーが発生したりするようになるかもしれません
> なので、少し難しいかもしれません
> ゲームのプロジェクトを送ることならできそうです
zlib を使用しただけのプログラムではエラーが発生せず、『ゲーム内の別のプログラムに問題』がある場合は
申し訳ありませんがご自分の力で原因を探してください m(_ _;m
( その場合『圧縮について』や『zlib の使い方について』というテーマではなく、一般的なバグ修正になりますので… )
|
Re: 圧縮したい ( No.12 ) |
- 名前:にこよん 日時:2017/10/15 23:16
> そういえば、『元データと同じサイズ分』ではなく『元データの2倍のサイズ分』にした場合もエラーは発生しますでしょうか?
発生しませんでした
2倍にしても3倍にしても発生せず、10倍なんかにしてみても正常に動きました
(0.8、0.6倍だとエラーが発生)
> zlib を使用しただけのプログラムではエラーが発生せず、『ゲーム内の別のプログラムに問題』がある場合は
> 申し訳ありませんがご自分の力で原因を探してください m(_ _;m
ゲームが関係なさそうなら、と思ってたのですが...すみません
> ( その場合『圧縮について』や『zlib の使い方について』というテーマではなく、一般的なバグ修正になりますので… )
理解しています
さすがにゲームのバグ探しは人に頼もうとは思いません(;´・ω・)
もし原因がバッファオーバーランならメモリを確保した後から圧縮するまでの間のプログラムですよね?
何度も見返したのですがそのようなことが起こることはなさそうです
やはり原因はわかりません
|
Re: 圧縮したい ( No.13 ) |
- 名前:管理人 日時:2017/10/15 23:24
> もし原因がバッファオーバーランならメモリを確保した後から圧縮するまでの間のプログラムですよね?
いえ、『ゲームに組み込んだ場合にしかエラーが発生しない』のであれば、ゲームのプログラムの
どこかでバッファオーバーランしていて、たまたま圧縮プログラムの箇所でエラーが発生しただけの可能性があります
なので、ゲームプログラムのどこかでバッファオーバーランしていた場合は『zlib を使った箇所でエラーが発生した』からと言って
『zlib を使っている箇所に原因がある』とは限りません
|
Re: 圧縮したい ( No.14 ) |
- 名前:にこよん 日時:2017/10/17 01:14
> いえ、『ゲームに組み込んだ場合にしかエラーが発生しない』のであれば、ゲームのプログラムの
> どこかでバッファオーバーランしていて、たまたま圧縮プログラムの箇所でエラーが発生しただけの可能性があります
ゲームを起動した瞬間から圧縮するまでのどこか分からないという意味でしょうか?
それとも圧縮のクラスを定義した後のゲームのプログラムの可能性があるという意味でしょうか?
もし1行目なら修正はほぼ不可能に思えるのでメモリを無駄に確保して、バグが起きにくいようにするなどのお応急処置をとろうと思います。
|
Re: 圧縮したい ( No.15 ) |
- 名前:管理人 日時:2017/10/18 00:44
> ゲームを起動した瞬間から圧縮するまでのどこか分からないという意味でしょうか?
> それとも圧縮のクラスを定義した後のゲームのプログラムの可能性があるという意味でしょうか?
1行目です
『ゲームに組み込んだ場合にしかエラーが発生しない』のであれば、圧縮処理以外の
箇所に原因がある可能性は高いと思います
> もし1行目なら修正はほぼ不可能に思えるのでメモリを無駄に確保して、バグが起きにくいようにするなどのお応急処置をとろうと思います。
修正が難しい部類のバグですね…
|
Re: 圧縮したい ( No.16 ) |
- 名前:にこよん 日時:2017/10/19 00:58
> 1行目です
マジですか....
しばらく試行錯誤しようと思います。
ありがとうございました。
|
Re: 圧縮したい ( No.17 ) |
- 名前:にこよん (解決) 日時:2017/10/29 02:18
解決に忘れでした
|
|