Program Organization/ Array's vs Structs etc

From Visual Basic to GNU C, this is the place to talk programming.

Moderators: SecretSquirrel, just brew it!

Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 2:36 pm

I got a couple of programming questions that I thought I could get some help here. I am programming in C, and I am trying to determine
if I am better off using Structures or Array's to store and present the data. Currently I am using array's but it is getting to be a pain to keep track
of everything. It basically acts a monitor circuit and certain events trip as they occur.

I am not that great of a programmer, but I am trying to broaden my horizons as my job is requiring me to learn a lot more

Basically my pseudocode is the following:

Code: Select all
Get Battery1 Voltage
Get Battery1 Current
Get Battery1 Status
Get Battery1 ...N
...
Get BatteryN Voltage


Basically it would fill an array/matrix ~16x20

Process the data (Better for structs or arrays)

Output the data linearly like this

Code: Select all
Output[0] = Value1
Output[1] = Value2
...
Output[35] = Battery1 Voltage
Output[240] = Battery16 N


Currently I have array's loop through saving in each individual part of the array after I convert them to the appropriate data type. So something like this:

Code: Select all
for(i = 0; i< TotalBatteryNumber; i++)
// Loop through each battery
{
   GetVoltage(BatteryNumber)
   // Function gets the battery voltage
   {      
         BatteryArray[i][0] = Voltage;
         // Inside the function basically does this
   }
}

Then I do the same thing for the Current, Status, etc.

I would then process the data and then output it on my Output loop using similar for loops. I was wondering if a structure like this is more efficient and easier to read:

Code: Select all
struct Batterys{
      int Voltage;
      int Current;
      int Status;
      int ...
   } Battery1, Battery2, Battery3, BatteryN;

Or would it be better like this:
Code: Select all
struct Voltage{
   int Battery
   } Battery1, Battery2, Battery3, BatteryN;

struct Current{
   int Battery
   } Battery1, Battery2, Battery3, BatteryN;

Or if someone has a better idea to collect, organize and process the data for output. The other thing is my Output data can only send 16 bytes at a time through the serial bus
it interfaces with so I was trying to use a counter for that.

The only thing I am not that comfortable with is pointers and references. I have been trying to get a grasp on it, but it is taking me a while.

This is for a DSP embedded solution with actual hardware. I am just trying to get some opinions on how to best organize the data.

Thanks for the help.
To Start Press Any Key'. Where's the ANY key?
If something's hard to do, then it's not worth doing
You know, boys, a nuclear reactor is a lot like a woman. You just have to read the manual and press the right buttons.
mmmmmdonuts21
Gerbil Elite
 
Posts: 590
Joined: Wed Jul 16, 2008 9:09 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 4:06 pm

[I have a very object oriented view of the world]

I would recommend using an array of these (to mimic an OOP class).
mmmmmdonuts21 wrote:
Code: Select all
struct Batterys{
      int Voltage;
      int Current;
      int Status;
      int ...
   } Battery1, Battery2, Battery3, BatteryN;



Access could then be something like
Code: Select all
for(i = 0; i< TotalBatteryNumber; i++)
// Loop through each battery
{
   GetVoltage(BatteryNumber)
   // Function gets the battery voltage
   {     
         BatteryArray[i].voltage = Voltage;
         // Inside the function basically does this
   }
}

or whatever you actually need it to do.

As I said at the beginning of my post, I have an OOP background, and usually try to make C mimic a true OOP language. Yes, the struct doesn't have the associated methods, or any notion of polymorphism or inheritance, but it's better organized and will scale better than 2D arrays.
Lenovo W520
IBM dx340
Nokia Lumia 928
Sony a7 with far too many lenses to list or even count
lonleyppl
Gerbil XP
 
Posts: 343
Joined: Wed Jan 26, 2011 2:59 pm

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 4:07 pm

Does that 16 bytes cover all the data per battery?

You need to be a bit more specific as to what "better" is. More readable code? Faster reading of the data from the serial bus? Tighter for loop?

The fastest is if you can directly memory map a structure to the memory, then all you need is to just memcpy the data into the beginning address of the struct and it will be automagically filled. However, you have to account for bit fields and compiler auto-padding of member fields. That is assuming the data comes in per battery.

However, if the data stream you get is all voltages, then all currents, etc. then may be your approach makes better sense.

Are we doing work for you or is this some kind of pet project?
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24285
Joined: Mon May 24, 2004 2:19 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 4:25 pm

The data stream is sent out via RS232 on a serial bus and basically I am filling unsigned bytes one by one to a buffer. The buffer is 16 bytes then I have send the stream and clear the buffer in order to fill the buffer with the next 16 bytes and so on and so forth. In total I have 351 + 2 checksumbytes that I send out at 1Hz at 19200 baud. Each battery of the 16 batteries has 20 bytes to be sent along the bus.

I basically have it working by using the arrays currently with tons of for loops like I demonstrated. I am just in the process of debugging at the system level and what I am finding is I am accessing quite a few wrong spots on the array and subsequentially calculate/output the wrong data which. I guess what I mean by better is what is easier to read and faster to debug and the shortest code if at all possible.

My thought is structures would make it easier to read so other people (including myself) don't have to get bogged down verifying the correct location of the array's.

The project is something I am currently working on at my job where I basically got the short straw to program it because I know more C than anyone else (basically computer science 1). Like I said I guess it doesn't have to be so much for this project but I am trying to get a sense for the future on which would be a better way to attack it if any or if array's would be the best because I see more projects like this down the line and soon.
To Start Press Any Key'. Where's the ANY key?
If something's hard to do, then it's not worth doing
You know, boys, a nuclear reactor is a lot like a woman. You just have to read the manual and press the right buttons.
mmmmmdonuts21
Gerbil Elite
 
Posts: 590
Joined: Wed Jul 16, 2008 9:09 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 4:42 pm

One possibility is to move to C++ and use a map as a sort of associative array. Then you could reference things like this:

Code: Select all
std::map<std::string, int> values;
values["voltage"] = 12;
int current = values["current"];


This may be heavier than you're looking for. You could approximate something similar by using defines or enums:

Code: Select all
enum eNames
{
    eNameVoltage = 0,
    eNameCurrent,
    etc....
    eNameMaxValue
};

int values[eNameMaxValue];
values[eNameVoltage] = 12;
int current = values[eNameCurrent];


Apologies for any syntax errors -- totally freehanded.

The problem with structs is keeping them in sync with code if changes are made (not that you don't have a lesser but similar problem with the enum). But the advantage, of course, is that the space is pre-allocated and named, which is good.

The problem with arrays is that they are completely disassociated from the data they hold, so you have to be careful to make sure they are the right size and that the values you are indexing are actually at the location you expect.

The advantage to the associative array example is that the space is allocated dynamically, and the name always refers back to the expected value. You could also use an enum instead of a string for the key in the map, to make it more efficient. But of course, to go this route you need to move to C++.
Buub
Maximum Gerbil
Silver subscriber
 
 
Posts: 4191
Joined: Sat Nov 09, 2002 11:59 pm
Location: Seattle, WA

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 4:58 pm

So how is the data ordered in the stream from the serial line? Is it like: voltage(1), current(1), status(1), ... voltage(2), current(2)...? Is the buffer big enough for all data from one battery?

Since this is a DSP embedded system, is C++ even available?

Structs should be better readability wise, but the layout may not be conducive to reading the data from the buffers. How many fields of data are we talking about per battery? You may also need to consider protocol overhead with your target hardware, since you may run into performance issue if you choose to get voltages from different batteries rather than reading all data from 1 battery and then move on to the next (or it can be the other way around).
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24285
Joined: Mon May 24, 2004 2:19 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 5:33 pm

Flying Fox wrote:So how is the data ordered in the stream from the serial line? Is it like: voltage(1), current(1), status(1), ... voltage(2), current(2)...? Is the buffer big enough for all data from one battery?

Since this is a DSP embedded system, is C++ even available?

Structs should be better readability wise, but the layout may not be conducive to reading the data from the buffers. How many fields of data are we talking about per battery? You may also need to consider protocol overhead with your target hardware, since you may run into performance issue if you choose to get voltages from different batteries rather than reading all data from 1 battery and then move on to the next (or it can be the other way around).


Unfortunately C++ is not available. It is straight C because of the embedded system.

The Battery Line would be exactly the way you presented it.

So the batteries I am using are using the SMBus protocol (similar to I2C and basically a the bus all smart batteries read from) and I have to read in one or two signed/unsigned bytes depending on what data I am reading in. For instance, voltage is unsigned two bytes and current is signed two bytes. I then cycle through a battery getting all the data at once and then transforming that information to be sent on the output for that particular battery.

So basically:

Read Voltage(1), Read Current(1),... Read LastByte(1) --> Process Data from batteries --> Save the data in the output buffer to be sent out on the next timer interrupt --> go to the next battery until the last battery and loop around again forever

In there there would be an interrupt that would occur periodically throughout the cycle. As far as the output buffer goes I could split it up in two parts if need be.

I guess I was mainly just curious if there was an easier coding structure to process the data, but array's look like it might be the easiest solution. Thanks for the help.
To Start Press Any Key'. Where's the ANY key?
If something's hard to do, then it's not worth doing
You know, boys, a nuclear reactor is a lot like a woman. You just have to read the manual and press the right buttons.
mmmmmdonuts21
Gerbil Elite
 
Posts: 590
Joined: Wed Jul 16, 2008 9:09 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 5:41 pm

Flying Fox wrote:Since this is a DSP embedded system, is C++ even available?

C++ is becoming increasingly available and used in embedded systems, but it's not available everywhere. Looks like it's not an option here, but there are some places where it is.
Buub
Maximum Gerbil
Silver subscriber
 
 
Posts: 4191
Joined: Sat Nov 09, 2002 11:59 pm
Location: Seattle, WA

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 6:01 pm

Buub wrote:
Flying Fox wrote:Since this is a DSP embedded system, is C++ even available?

C++ is becoming increasingly available and used in embedded systems, but it's not available everywhere. Looks like it's not an option here, but there are some places where it is.

Yup... but on some low-cost microcontrollers there isn't enough program or data memory to support the additional overhead.

There are also potential verification issues for safety-critical systems -- it is harder to "prove" (to the satisfaction of the relevant regulatory agencies) that a piece of code is correct when you're using a more complex language like C++. At my day job we routinely use C (even though C++ is available on our platform) for this reason.
(this space intentionally left blank)
just brew it!
Administrator
Gold subscriber
 
 
Posts: 37479
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 6:05 pm

just brew it! wrote:At my day job we routinely use C (even though C++ is available on our platform) for this reason.

I'd have thought you'd be stuck with Ada, or did that project finally crater?
It is one of the blessings of old friends that you can afford to be stupid with them. Ralph Waldo Emerson.
Captain Ned
Global Moderator
Gold subscriber
 
 
Posts: 20103
Joined: Wed Jan 16, 2002 7:00 pm
Location: Vermont, USA

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 6:20 pm

It sounds like you want an array of struts. Have a struct represent a battery, and then create an array of batteries

Code: Select all
typedef struct {
      int Voltage;
      int Current;
      int Status;
      int ...
} Battery;


int ReadBattery(battery* b, int* buffer)
{
    b->Voltage = buffer[0];
    b->Current = buffer[1];
    ...
}

Battery batteries[16];

batteries[4].Voltage = 24;



Equally you could use a struct of arrays

Code: Select all
#define NBATTERIES 16

struct
{
    int voltages[NBATTERIES];
    int current[NBATTERIES];
} Batteries;

Batteries.voltages[4]= 24;

But the first is generally going to be more readable, and is far more useful if you want to build functions that operate on a single battery. The second might be slightly faster if you want to write functions that operate on all the batteries, say to find the lowest voltage. Or if you send all the voltages through the bus, then all the currents. But in general you want to write readable code before fast code.

And you really want to use arrays instead of having battery1, battery2, battery3.. battery16
mboza
Gerbil Team Leader
 
Posts: 203
Joined: Fri Sep 15, 2006 6:52 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 6:22 pm

Captain Ned wrote:
just brew it! wrote:At my day job we routinely use C (even though C++ is available on our platform) for this reason.

I'd have thought you'd be stuck with Ada, or did that project finally crater?

It's still used in some systems (though not by us). I wouldn't go so far as to say it has completely cratered, but the Pentagon's dream of having a standardized programming language for all military systems has gone out the window, a victim of the push to control costs through the use of COTS (Commercial Off-The-Shelf) tech. Heck, we're even running on an Intel processor; until pretty recently it was practically unheard of to have anything that wasn't PowerPC-based in a military application.

Edit: At least we're not running Windows on it; remember that story a few months back about the military's drone control systems being infected with keyloggers? :lol:
(this space intentionally left blank)
just brew it!
Administrator
Gold subscriber
 
 
Posts: 37479
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 7:28 pm

Buub wrote:
Flying Fox wrote:Since this is a DSP embedded system, is C++ even available?

C++ is becoming increasingly available and used in embedded systems, but it's not available everywhere. Looks like it's not an option here, but there are some places where it is.
I am aware of that. In fact the only real embedded system that I did before was on the MPC platform which has Embedded C++ support (no template and all the weird C++ stuff at the time).

mmmmmdonuts21 wrote:
Flying Fox wrote:So how is the data ordered in the stream from the serial line? Is it like: voltage(1), current(1), status(1), ... voltage(2), current(2)...? Is the buffer big enough for all data from one battery

The Battery Line would be exactly the way you presented it.

So the batteries I am using are using the SMBus protocol (similar to I2C and basically a the bus all smart batteries read from) and I have to read in one or two signed/unsigned bytes depending on what data I am reading in. For instance, voltage is unsigned two bytes and current is signed two bytes. I then cycle through a battery getting all the data at once and then transforming that information to be sent on the output for that particular battery.

So basically:

Read Voltage(1), Read Current(1),... Read LastByte(1) --> Process Data from batteries --> Save the data in the output buffer to be sent out on the next timer interrupt --> go to the next battery until the last battery and loop around again forever

In there there would be an interrupt that would occur periodically throughout the cycle. As far as the output buffer goes I could split it up in two parts if need be.

The only point where I can see potential speedup is if you can read all the data related to 1 battery in one shot, based on that 16-byte buffer that you were talking about. Then in your "process buffer" function, with pointer arithmetic and (!) raw casting to assign values to your struct. If you have to go "read 2 byte as signed/unsigned integer" one value at a time, then there won't be a lot of speedup. The struct approach does seem more logical and readable. Are integers 32-bit on your platform or are we dealing with some weird-ass alignment crap? The fastest is if you can map that structure directly onto the memory buffer (alignment/padding/bitness/endian issues aplenty), not sure if that is available since you have not really answered that.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24285
Joined: Mon May 24, 2004 2:19 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Wed Dec 19, 2012 9:28 pm

I would go with an array of structs (mboza's first option).

Flying Fox - I haven't seen any mention of a speed / cpu load issue here and I'm concerned that you are looking for premature optimisation (which is the root of all evil :) ). I always write the simplest cleanest code I can and see how that runs, then start optimising it if required. If it runs fine then I leave it alone so it is super simple to debug when anyone comes back to it a few years down the road. Over the years I have had to debug too many piles of buggy hand optimised garbage that actually run slower than clean code optimised by the compiler to consider doing anything else.
notfred
Grand Gerbil Poohbah
 
Posts: 3711
Joined: Tue Aug 10, 2004 10:10 am
Location: Ottawa, Canada

Re: Program Organization/ Array's vs Structs etc

Postposted on Thu Dec 20, 2012 2:10 am

notfred wrote:Flying Fox - I haven't seen any mention of a speed / cpu load issue here and I'm concerned that you are looking for premature optimisation (which is the root of all evil :) ). I always write the simplest cleanest code I can and see how that runs, then start optimising it if required. If it runs fine then I leave it alone so it is super simple to debug when anyone comes back to it a few years down the road. Over the years I have had to debug too many piles of buggy hand optimised garbage that actually run slower than clean code optimised by the compiler to consider doing anything else.

That's why I asked him what "better" means right off the bat.

However, usually in the embedded world, I see common constructs like:
Code: Select all
/* assume everything is 2-byte short
typedef struct BatteryDataType
{
  short voltage;
  unsigned short current;
  short C;
  short D;
  short E;
  short F;
  short G;
  short H;
} BatteryData;

/****/
int i;
unsigned char buffer[16];
BatteryData BatteryDataArray[5]; /* assume 5 */
BatteryData* p = BatteryDataArray;
for (i = 0; i < sizeof(BatteryDataArray)/sizeof(BatteryDataArray[0]); ++i)
{
  ReadBufferFromHardware(buffer, sizeof(buffer)/sizeof(buffer[0]));
  /* assume no error */
  memcpy(p, buffer, sizeof(BatteryData));
  ++p;
}
Of course if the data format changes you have to keep up to date, but that's how I have seen people done almost as their first attempt. Now if the data do come in 2 bytes at a time then we will have to assign the numbers field by field, which still means the array of structs make more sense.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24285
Joined: Mon May 24, 2004 2:19 am

Re: Program Organization/ Array's vs Structs etc

Postposted on Thu Dec 20, 2012 2:04 pm

It's not at all relevant here, or in the context of embedded and/or IO in general, but given the title I should just mention that in HPC or other context where extensive time-critical computation is required (eg gaming), the Array of Struct construct, while far more intuitive, isn't conducive to things like SIMD (at least in the absence of a GATHER instruction). For that reason in those contexts the Struct of Arrays data structure is more common.
UberGerbil
Gerbil Khan
 
Posts: 9970
Joined: Thu Jun 19, 2003 3:11 pm

Re: Program Organization/ Array's vs Structs etc

Postposted on Fri Dec 21, 2012 7:44 am

Code: Select all
typedef batteryData_t union {
  uint8_t raw_data[16];
  struct {
    uint16_t Voltage;
    uint16_t Current;
    uint16_t Status;
    uint16_t ...
}

batteryData_t batteryData[16];


&batteryData[n].raw_data is a pointer to a 16 byte buffer in which you dump the raw data coming over the serial bus. You can then access that various values as batteryData[n].Voltage, batteryData[n].Status, etc. As others pointed out, this assumes a static ordering to the raw data stream, but so would just about any other solution unless the data stream contains key value pairs. The uint8 and uint16 data types or something similar are probably defined for your platform. They are pretty common in embedded systems where the data width of "int" is somewhat different than a full blown processor.

One slight suggestion -- get comfortable with pointers. You need them, especially in an embedded system where program memory may be precious. You need them to write C code that does anything of real complexity.

--SS
SecretSquirrel
Gerbil Jedi
Gold subscriber
 
 
Posts: 1686
Joined: Tue Jan 01, 2002 7:00 pm
Location: The Colony, TX (Dallas suburb)

Re: Program Organization/ Array's vs Structs etc

Postposted on Mon May 06, 2013 7:58 am

This reminds me of when I used to program JASS scripts for WarCraft 3 and the community had a pre-compiler that accepted pseudo code and converted it into true code for Blizzard's interpreters to work with.

Basically you would write something like this:

Code: Select all
struct myStruct
    integer i = 0
endstruct


And It would compile to something like this, because JASS, the language WarCraft 3 uses, does not support OOP nor private variables for that matter (warning - verbose stuff ahead):

Code: Select all
globals
    integer array myStruct__i
    integer array myStruct__recycle
    integer myStruct__count
endglobals
   
        function myStruct__allocate takes nothing returns integer
            local integer this
   
            if myStruct__recycle[0] == 0 then
                if myStruct__count == 8190 then //in JASS, arrays are limited to 8192 indices and the 8192nd index bugs when loading from a saved game so we don't use it
                    return 0
                endif
                set myStruct__count = myStruct__count + 1
                set this = myStruct__count
            else
                set this = myStruct__recycle[0]
                set myStruct__recycle[0] = myStruct__recycle[myStruct__recycle[0]]
            endif

            set myStruct__recycle[this] = -1
   
            return this
        endfunction
   
        function myStruct__deallocate takes integer this returns nothing
            if myStruct__recycle[this] != -1 then
                return
            endif

            set myStruct__recycle[this] = myStruct__recycle[0]
            set myStruct__recycle[0] = this
        endfunction


All this is to say, you CAN use arrays instead of structs, but it's often easier to just use OOP.
Star Brood
Gerbil First Class
Silver subscriber
 
 
Posts: 180
Joined: Wed Mar 21, 2012 4:57 am


Return to Developer's Den

Who is online

Users browsing this forum: No registered users and 3 guests