Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Struct with array of struct and __attribute__((packed)) #1866

Closed
wiesener opened this issue Dec 10, 2019 · 5 comments
Closed

Struct with array of struct and __attribute__((packed)) #1866

wiesener opened this issue Dec 10, 2019 · 5 comments
Labels
kind: question state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated

Comments

@wiesener
Copy link

wiesener commented Dec 10, 2019

What is the issue you have?

"cannot bind packed field".

Please describe the steps to reproduce the issue. Can you provide a small but working code example?

I've tried to cast a json dataset to a custom struct which is attribute packed and includes an array of type enum and an array of structs.

What is the expected behavior?

That it should cast the dataset with the given to_json and from_json functions.

And what is the actual behavior instead?

It does not compile with the following errors:

../src/main.cpp:37:23: error: cannot bind packed field ‘p.data_t::dur’ to ‘unsigned int&’
../src/main.cpp:38:23: error: cannot bind packed field ‘p.data_t::seq’ to ‘unsigned int&’
../src/main.cpp:39:24: error: cannot bind packed field ‘p.data_t::mode’ to ‘unsigned int (&)[5]’
../src/main.cpp:40:26: error: no matching function for call to ‘nlohmann::basic_json<>::get_to(internal_data_t [2]) const’

json.hpp:17270:25: error: no type named ‘type’ in ‘struct std::enable_if<false, int>’
json.hpp:17282:72: error: no type named ‘type’ in ‘struct std::enable_if<false, int>’
....

Which compiler and operating system are you using? Is it a supported compiler?
gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0

Did you use a released version of the library or the version from the develop branch?
released

If you experience a compilation error: can you compile and run the unit tests?
Yes the unit tests run fine.

Minimal example:

main.cpp:

// json handling
#include <iostream>

#include <stdint.h>

typedef struct __attribute__((packed)){
uint8_t nop;
uint16_t start[5];
uint16_t end[5];
} internal_data_t;

typedef enum __attribute__((packed)){
	FOOBAR = 0,
	BAZ = 1
} foo_t;

typedef struct __attribute__((packed)){
uint32_t dur;
uint32_t seq;
mode_t mode[5];
internal_data_t dat[2];
} data_t;

#include <fstream>
#include "json.hpp"

using namespace std;

void to_json(json& j, const data_t& p) {
	j = json{{"dur", p.dur}, {"seq", p.seq},
		{"mode", p.mode}, {"dat", p.dat}
	};
}

void from_json(const json& j, data_t& p) {
	j.at("dur").get_to(p.dur);
	j.at("seq").get_to(p.seq);
	j.at("mode").get_to(p.mode);
	j.at("dat").get_to(p.dat);
}


int main(int argc, char **argv)
{
	// Stimulator is connected but not idle
	std::ifstream file("test.json");
	json dat_json;
	file >> dat_json;
	std::cout << dat_json << std::endl;

	auto dat = dat_json.get<data_t>();

    return 0;
}

test.json:

{
"dur": 36000,
"seq": 1000,
"mode": [83, 83, 83, 83, 0],
"dat": [
{
"nop": 1,
"start": [150, 0, 0, 0, 0],
"end": [300, 0, 0, 0, 0]
},
{
"nop": 1,
"start": [150, 0, 0, 0, 0],
"end": [300, 0, 0, 0, 0]
}
]
}
@nlohmann
Copy link
Owner

In order to asses your issue, we need the following information:

  • What is the issue you have?

  • Please describe the steps to reproduce the issue. Can you provide a small but working code example?

  • What is the expected behavior?

  • And what is the actual behavior instead?

  • Which compiler and operating system are you using? Is it a supported compiler?

  • Did you use a released version of the library or the version from the develop branch?

  • If you experience a compilation error: can you compile and run the unit tests?

@nickaein
Copy link
Contributor

../src/main.cpp:37:23: error: cannot bind packed field ‘p.data_t::dur’ to ‘unsigned int&’

The cannot bind packed field errors occurs since get_to() accepts an l-value reference but you cannot get a reference to objects with alignment requirements (more info).

One solution is to use get<T>() and assignment:

p.dur = j.at("dur").get<uint32_t>();
p.seq = j.at("seq").get<uint32_t>();
...

../src/main.cpp:40:26: error: no matching function for call to ‘nlohmann::basic_json<>::get_to(internal_data_t [2]) const’

You also need to provide a to_json() implementation for internal_data_t type so that the library knows how to convert data_t::dat field (which is of type internal_data_t) into JSON object.

@wiesener
Copy link
Author

wiesener commented Dec 11, 2019

Thanks for the hint. I've changed it but still getting errors:```

void to_json(json& j, const data_t& p) {
	j = json{{"dur", p.dur}, {"seq", p.seq},
		{"mode", p.mode}, {"dat", p.dat}
	};
}

void to_json(json& j, const internal_data_t& p) {
	j = json{{"nop", p.nop}, {"start", p.start},
		{"end", p.end}
	};
}


void from_json(const json& j, data_t& p) {
	p.dur = j.at("dur").get<uint32_t>();
	p.seq = j.at("seq").get<uint32_t>();
	p.mode = j.at("mode").get<mode_t>();
	p.dat = j.at("dat").get<internal_data_t>();
}

Error message:
../src/main.cpp:45:36: error: incompatible types in assignment of ‘unsigned int’ to ‘mode_t [5] {aka unsigned int [5]}’
p.mode = j.at("mode").get<mode_t>();
^
../src/main.cpp:46:43: error: no matching function for call to ‘nlohmann::basic_json<>::get<internal_data_t>() const’
p.dat = j.at("dat").get<internal_data_t>();

and:
error: no type named ‘type’ in ‘struct std::enable_if<false, int>’

I guess there is something missing to tell the compiler that it is an array.

@nickaein
Copy link
Contributor

For arrays, the library accepts T = std::vector<T> type for get<T>(). I doubt the fixed-size arrays are supported given that JSON only supports variable-length arrays. Also given that the arrays are packed too, I believe the only way to use an intermediate std::vector object, e.g.:

    auto mode_vec = j.at("mode").get<std::vector<mode_t>>();
    for(size_t i=0; i<mode_vec.size(); i++)
    {
        p.mode[i] = mode_vec[i];
    }

Here is a minimal working code: https://wandbox.org/permlink/cj2Mn1k6dKnjrxch

@stale
Copy link

stale bot commented Jan 10, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated label Jan 10, 2020
@stale stale bot closed this as completed Jan 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: question state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated
Projects
None yet
Development

No branches or pull requests

3 participants