Re: Problem reading branches of structs

From: Andrea 'fwyzard' Bocci <Andrea.Bocci_at_cern.ch>
Date: Mon, 02 May 2005 01:38:50 +0200


Rene Brun wrote:

> Hi Andrea,
> 
> Your example is totally different of your first example.
> It mixes basic types of different sizes. 

My first example was identical: an unsigned int followed by some doubles. Same here.

I *did* find out what the problem is, and I consider it a root/cint bug. I was only asking if it is a known bug (aka "expected behaviour"): ie. if root/cint is supposed to have an allignment policy different from the compiler it uses / is compiled with.

Maybe this could be documented it in the ROOT User's Manual as an explicit "don't do this" case - it costed us a couple days of debugging and it could be useful for others to know it.

Anyway, we'll use a consistent behaviour from now on (ie., always use compiled code and possibly use classes).

Cheers,
.Andrea.

In this case,

> you will get alignment problems. You must go via a class
> instead of a struct to get a correct support in both C++ and CINT.
> Note that although your example works with C++, it will
> be very inefficient because the compiler will have to
> align your double anyhow.
> 
> Rene Brun
> 
> On Wed, 
> 27 Apr 
> 2005, Andrea Bocci wrote:
> 
> 

>>>Andrea,
>>>
>>>I do not understand your argument that:
>>>"gcc keeps the struct fields aligned to 4 bytes boundary"
>>>This is impossible with your struct.
>>
>>Well, in the comiled code, sizeof(bTagInfo) is 68, while in ROOT/CINT it is 72. So, different packing and allignement is applied.
>>
>>
>>>Could you replace
>>>
>>> tree->SetBranchAddress ("bTagInfo", &info);
>>>by
>>> tree->SetBranchAddress ("bTagInfo", &info.jet_E);
>>
>>But this would completely de-allign (either of 4 or 8 bytes) the struct in memory with the one in the root file.
>>
>>
>>>Note that we keep discouraging users to use structs instead
>>>of classes. With a class and its dictionary, you will simplify
>>>your interface when defining the branch: no need to specify
>>>the names of the data members since they are already known
>>>by the dictionary, and in addition you will get support
>>>for correct alignment of members in the class.
>>
>>I know, and I usually do it, but I wanted a simpler solution, without the need of an external (however simple) library.
>>I guess that saying that this is not supported is an acceptable solution - I can either compile all my applications (I usually do it), or use a class with a dictionary. Anyway:
>>
>>
>>>if you do not solve your problem, please send the shortest
>>>possible system reproduding it.
>>
>>here is a simple tet case, which show the same behaviour.
>>Again, sizof(XData) is 12 with gcc, but 16 with root.
>>
>>--- XData.h -------------------------------------------------
>>#ifndef XData_h
>>#define XData_h
>>
>>struct XData {
>> unsigned int an_int;
>> double a_double;
>>};
>>
>>#endif // XData_h
>>-------------------------------------------------------------
>>
>>--- write.cc ------------------------------------------------
>>#include <TFile.h>
>>#include <TTree.h>
>>
>>#include "XData.h"
>>
>>void write (void) {
>> TFile* file = new TFile("test.root", "RECREATE");
>> TTree* tree = new TTree("Test", "Test tree for a simple structure");
>>
>> XData data;
>> tree->Branch("XData", &data, "an_int/i:a_double/D");
>>
>> for (unsigned int i=0; i < 10; i++) {
>> data.an_int = i;
>> data.a_double = i;
>> tree->Fill();
>> }
>> tree->Write();
>> file->Close();
>>}
>>
>>int main (int argc, const char** argv) {
>> write();
>> return 0;
>>}
>>-------------------------------------------------------------
>>
>>and
>>
>>--- read.cc -------------------------------------------------
>>#include <iostream>
>>using namespace std;
>>
>>#include <TFile.h>
>>#include <TTree.h>
>>
>>#include "XData.h"
>>
>>void read (void) {
>> TFile* file = new TFile("test.root");
>> TTree* tree = (TTree*) file->Get("Test");
>>
>> XData data;
>> tree->SetBranchAddress("XData", &data);
>>
>> for (unsigned int i=0; i < 10; i++) {
>> tree->GetEvent(i);7
>> cout << data.an_int << '\t' << data.a_double << endl;
>> }
>> file->Close();
>>}
>>
>>int main (int argc, const char** argv) {
>> read();
>> return 0;
>>}
>>-------------------------------------------------------------
>>
>>compiled with
>> g++ -O2 $(root-config --cflags --libs) write.cc -o write
>> g++ -O2 $(root-config --cflags --libs) read.cc -o read
>>using GCC 3.2.3 and ROOT 3.10/02 (I've tried ROOT 4.x, same behaviour).
>>
>>If I do:
>> ./write
>> ./read
>>
>>I get:
>> 0 0
>> 1 1
>> 2 2
>> 3 3
>> 4 4
>> 5 5
>> 6 6
>> 7 7
>> 8 8
>> 9 9
>>
>>
>>If I do:
>> ./write
>> root read.cc
>>
>>I get:
>> Processing read.cc...
>> 0 3.39519e-313
>> 1 3.44819e-313
>> 2 3.44824e-313
>> 3 3.44827e-313
>> 4 3.44829e-313
>> 5 3.44831e-313
>> 6 3.44832e-313
>> 7 3.44833e-313
>> 8 3.44835e-313
>> 9 3.44835e-313
>>
>>which doesn't look correct...
>>
>>I get something similar if I do:
>> root write.cc read.cc
>>
>>While with:
>> root write.cc
>> ./read
>>
>>I get:
>> Processing write.cc...
>> 0 0
>> 1 0
>> 2 0
>> 3 0
>> 4 0
>> 5 0
>> 6 0
>> 7 0
>> 8 0
>> 9 0
>>
>>(prompt lines removed, of course).
>>
>>Thanks for your time and replies !
>>
>>.Andrea.
>>
>>

>
>
-- 

Andrea 'fwyzard' Bocci - Andrea.Bocci_at_cern.ch
Università di Firenze - Dipartimento di Fisica
Received on Mon May 02 2005 - 01:39:59 MEST

This archive was generated by hypermail 2.2.0 : Tue Jan 02 2007 - 14:45:07 MET