質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

3886閲覧

可変長のバイナリデータを読み込みたい

daiki002

総合スコア68

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

0クリップ

投稿2021/10/27 07:17

編集2021/10/27 07:18

前提・実現したいこと

バイナリデータを読み込みたいです。

バイナリデータ構造

イメージ説明

発生している問題・エラーメッセージ

固定長であればキャストで簡単に読み込めると思いますが、可変長になっているので単純なキャストでは「ズレ」が発生して上手く読み込めません。
固定長にしたいところですが元のバイナリデータは変更不可能です。

可変長のバイナリデータの場合どのように読み込む方法があるでしょうか?

該当のソースコード

cpp

1#include <iostream> 2 3#pragma pack(1) 4struct User 5{ 6 uint8_t id; 7 uint8_t name_length; 8 char *name; 9 uint8_t age; 10}; 11 12struct Users 13{ 14 uint8_t length; 15 User info[]; 16}; 17#pragma pack() 18 19int main() 20{ 21 uint8_t data[] = { 22 0x02, 23 0x01, 0x07, 0x74, 0x61, 0x6E, 0x61, 0x6B, 0x61, 0x31, 0x01, 24 0x02, 0x08, 0x74, 0x61, 0x6E, 0x61, 0x6B, 0x61, 0x31, 0x31, 0x02 25 }; 26 27 auto users = reinterpret_cast<Users*>(data); 28 std::printf("userInfos.length: %d\n", users->length); 29 30 for (auto i = 0; i < users->length; i++) 31 { 32 auto user = reinterpret_cast<User*>(&users->info[i]); 33 34 auto id = user->id; 35 auto nameLength = user->name_length; 36 std::string name(reinterpret_cast<char*>(&user->name), nameLength); 37 auto age = user->age; 38 39 std::printf("Id: %d\n", id); 40 std::printf("名前の長さ: %d\n", nameLength); 41 std::printf("名前: %s\n", name.c_str()); 42 std::printf("年齢: %d\n", age); 43 } 44 45 return 0; 46}

出力

userInfos.length: 2 Id: 1 名前の長さ: 7 名前: tanaka1 年齢: 107 Id: 97 名前の長さ: 49 名前: tanaka11フフフフフフ"跳4戍ル 年齢: 97

期待する出力

userInfos.length: 2 Id: 1 名前の長さ: 7 名前: tanaka1 年齢: 1 Id: 2 名前の長さ: 8 名前: tanaka11 年齢: 2

補足情報(FW/ツールのバージョンなど)

  • C++17
eien_beginner👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

C++

1#include <cstdint> 2#include <cstdio> 3#include <string> 4#include <iterator> 5#include <vector> 6 7struct User { 8 uint8_t id; 9 std::string name; 10 uint8_t age; 11}; 12 13int main() { 14 uint8_t data[] = { 15 0x02, 16 0x01, 0x07, 0x74, 0x61, 0x6E, 0x61, 0x6B, 0x61, 0x31, 0x01, 17 0x02, 0x08, 0x74, 0x61, 0x6E, 0x61, 0x6B, 0x61, 0x31, 0x31, 0x02 18 }; 19 20 std::vector<User> users; 21 22 auto in = std::begin(data); 23 uint8_t size = *in++; 24 while ( size-- ) { 25 User user; 26 user.id = *in++; 27 uint8_t name_length = *in++; 28 user.name = std::string(in, std::next(in, name_length)); 29 std::advance(in, name_length); 30 user.age = *in++; 31 users.push_back(user); 32 } 33 34 for ( const User& item : users ) { 35 std::printf("Id: %d\n", item.id); 36 std::printf("名前の長さ: %lld\n", item.name.size()); 37 std::printf("名前: %s\n", item.name.c_str()); 38 std::printf("年齢: %d\n", item.age); 39 } 40 41 return 0; 42}

投稿2021/10/27 08:38

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

daiki002

2021/10/27 09:01

ありがとうございます。 キャストが無理なのでint32_t氏の回答のように純粋にポインタで読み進めていくしかないかなと思っていましたがstd::begin, std::advanceが利用できるのですね。 C++らしい書き方が出来るのでこちらを利用します。 ありがとうございました。
guest

0

可変長のバイナリデータの場合どのように読み込む方法があるでしょうか?

このフォーマットの場合、キャストで構造体にすることはできません。
ポインタかインデックスを1つずつ進めながら入力データをパーズするしかないです。

例:

  • struct Users: 削除
  • struct User: name_length を削除
  • struct User: namestd::string にする
  1. const uint8_t*のポインタを data の先頭で初期化
  2. Userの数を読んで、ポインタをすすめる
  3. Userの数でループ

--User インスタンスを作成
-- ポインタが指す値を読んで User::id に格納、ポインタを進める
-- ポインタが指す値を読んで変数 nameLength に格納、ポインタを進める
-- ポインタが指すアドレスから長さ nameLength のエリアで std::string を作って User::name に格納。ポインタに nameLength を足す
-- ...

投稿2021/10/27 07:39

編集2021/10/27 07:42
int32_t

総合スコア21695

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

まずはバッファを用意しといてファイルのデータを読み込んでおき、そこからフォーマットに従って変数に読み込んでいけばいいです

struct User
{
uint8_t id;
uint8_t name_length;
char *name;
uint8_t age;
};

nameはポインタではダメです
char name[80];
とかデータの最大長の配列とし、そこにデータを読み込んでいく必要があります。
また、このデータが文字列なのであれば、その後端には'\0'を入れておく必要があります

投稿2021/10/27 07:20

編集2021/10/27 07:31
y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問