Is it possible to access struct fields dynamically in generated code?

Hello all,
I would like to know if it is possible to access struct fields dynamically in generated code as stated in the title. For that I provide a minimum example. In my case I need to load a JSON file which is translated to a structure and I don't know the fields in advance.
%% structure.json
{
"a": 0,
"bb": 0.1,
"ccc": [],
"dddd": {},
"eeeee": "abc",
"ffffff": 'abc',
"a1": 0,
"b2": 0.1,
"c3": [],
"d4": {},
"e5": "abc",
"f6": 'abc'
}
%% main.m
structure = struct;
structure.a = 0;
structure.bb = 0.1;
structure.ccc = [];
structure.dddd = {};
structure.eeeee = 'abc';
structure.ffffff = "abc";
prototype(structure);
prototype("structure.json");
%% prototype.m
function prototype(structure)
if isstruct(structure)
field_names = fieldnames(structure);
disp("field names count: " + length(field_names));
for i = 1:length(field_names)
disp("field name " + i + ": " + field_names{i});
end
disp("content of field name a: " + structure.a);
for i = 1:length(field_names)
if ~iscell(structure.(field_names{i})) && ~isnumeric(structure.(field_names{i}))
disp("dynamic access to content of field name " + field_names{i} + ": " + structure.(field_names{i}));
end
end
elseif ischar(structure) || isstring(structure)
json_file = fileread(structure);
json_content = jsondecode(json_file);
end
end
%% compile.m
structure = struct;
structure.a = 0;
structure.bb = 0.1;
structure.ccc = [];
structure.dddd = {};
structure.eeeee = 'abc';
structure.ffffff = "abc";
structure.a1 = 0;
structure.b2 = 0.1;
structure.c3 = [];
structure.d4 = {};
structure.e5 = 'abc';
structure.f6 = "abc";
cfg = coder.config('lib');
codegen -report -config cfg prototype...
-args structure...
-O disable:inline
cfg = coder.config('exe');
codegen -report -config cfg -args structure prototype codegen/lib/prototype/examples/main.c codegen/lib/prototype/examples/main.h
Many thanks in advance,
Nikita

1 件のコメント

Joris Brouwer
Joris Brouwer 2023 年 3 月 27 日
I just ran into the same boundary conditions. I have a JSON input in Matlab which works perfectly with dynamic fields. Now converting to C-code I need predefined fieldnames. Since my problem is not so big (and I knew very well this was a limitation before I started but I still had a go since each version coder is improved) I'll go for the hardcoded fieldnames. Just a tit bit more coding to do.
My preferred solutions would be jsondecode (and jsonencode) to be made an extended capability C/C++ code generation. But I understand that may be though one not getting the highest priority by the development team.

サインインしてコメントする。

 採用された回答

Denis Gurchenkov
Denis Gurchenkov 2020 年 2 月 21 日
The the specific question you are asking ("is possible to access struct fields dynamically in generated code"), the answer is "no". Where is why:
MATLAB Coder aims to translate MATLAB into statically typed C/C++ code, similar to what a human would write. To that extent, it translates MATLAB structures into C/C++ structs. In C and C++, the list of fields in a struct, each use of a field must be statically resolved.
So, whenever codegen sees "var.(field)", it wants to find out the value of the variable "field" at compile time. If it could not do so, it produces an error. Also, it wants to know, at compile time, what is the full list of fields in a struct.
If you elaborate on your intent (what you want to achieve, why you'd want to generate C/C++ code using MATLAB Coder and parse Json there) someone could suggest an alternative solution.
For instance, if you know the full list of fields ahead of time, and all the fields have same types, you could write something akin to
function out = dynFieldAccess(var, fieldname)
if strcmp(fieldname, 'a')
out = var.a;
else if strcmp(fieldname, 'b')
out = var.b;
else..
and so on.
Or maybe you'd be better off hand-writing the C/C++ code for this part of your application.

5 件のコメント

Nikita Balyschew
Nikita Balyschew 2020 年 2 月 21 日
My JSON file is a configuration file for a pipeline I am writing. This file is merged with another JSON file with default values. This fields I know in advance. The resulting structure is used to configure the pipeline modules. But the modules can also output some structure, which is merged into this structure and there some arbitrary naming can appear, which I think I could standardize somehow, but I would need to attach a number as a postfix to the fields with this standardized naming.
Would this mean that with your solution I would need to write a function which would also check fieldnames up to a certain number as a postfix, which is a upper bound of supported variables of this kind?
Denis Gurchenkov
Denis Gurchenkov 2020 年 2 月 21 日
Hi Nikita, so at the time when "codegen" command is run, do you have the "big" JSON file, with all the pipeline's possibly added fields in that file?
I mean, if for each particular case wehn you run codegen, you know the list of pipeline modules and can get all the extra fields, then, it looks like you can produce one giant struct and have codegen generate C code for it. A
If, however, the list of fields can't be known precisely, then I don't see how a C struct can be produced.
As you said, you can kinda make it work by imposing some naming discipline, so that during compilation codegen is told how may fields, what are field names etc.
PatrizioGraziosi
PatrizioGraziosi 2020 年 9 月 29 日
編集済み: PatrizioGraziosi 2020 年 9 月 29 日
Hi Denis,
I think I have a similar task and need to know if or how I can use the coder to port my function in C.
My application computes some properties of generic electronic materials, defined by the user, with a variable number of "bands", labelled according to their type, for example
bands = ['A','A','B','C','C','C'] ;
if the bands interact, a variable is entered by the user, if not, nothing is entered by the user, for example
AA_i = 3; AB_i = 5; BB_i = 2 ; CC_i = 4;
To be generic, the number of bands, as well as the number and type of interactions, is defined by the user.
The function
[outputs] = myfunction(mystruct) ;
simply reads the 'bands' labels and checks, for each pair of them, if the interaction is allowed
if isfield(mystruct,field_name) % field_name = 'AA_i' ...
% calculations
end
Thus, it is not possible to know in advance how many fields will be in mystruct.
In Matlab this is not a problem, but it looks like this becomes a problem when porting to C as I have to define all the possible names in the coder...isn't it?
Is there a possibility to addredd this task?
Thanks
Patrizio
Ryan Livingston
Ryan Livingston 2020 年 9 月 29 日
The concept that Denis describes above also holds here. When MATLAB Coder analyzes your code, it needs to be able to determine the full set of fields present in your struct during code generation. In the generated code, do you envision that your users would need to provide input to specify these pairs? Or could the user provide the input prior to code generation?
PatrizioGraziosi
PatrizioGraziosi 2020 年 9 月 30 日
Hi Ryan,
thank you!
the idea is to share the application in C, already finished, and the users enter the inputs and run the code.
At present, the inputs are in "free form", the user enters what is needed and the application checks them.
But if I understand, in order to share the application already in C, I should re-shape it to have pre-defined fields, is this correct?
Thanks
Patrizio

サインインしてコメントする。

その他の回答 (0 件)

製品

リリース

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by