Author Topic: Initializing a struct member with a certain value if left undefined  (Read 1440 times)

0 Members and 1 Guest are viewing this topic.

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Hallo ladies and gents,

yet again I want to ask a question regarding C.

I am using a struct to interface with a library I am writing, I want that if the user doesn´t initialize a member of the struct (which he/she is not supposed to initialize but rather only read
as information available at anytime to him/her) for that member to default to a certain value.

My case is this:
I´m using a struct to interface to a couple functions, specifically to initialize the CCP modules of a PIC in PWM mode using the XC8.

I have this struct:

typedef struct SimplePWM_Setup
{
    uint8_t CCP_Module;
    bool use_TMR4;
    uint16_t Max_Step;
    uint8_t Prescaler;
    int32_t Frequency;
    uint16_t Duty_Step;
};

The frequency is determined by some other values during the Init function. The user is not supposed to write the frequency, it should be a read only value to the user that can be accessed by
the init function to set the value.
I want the frequency to always be initialized to -1 as that would mean that the Init function is not yet run.
I don´t want to predetermine the the structs that are going to be used in the main program as for example, mainly for RAM considerations.

What can be the solution to my problem?
Thanks in advance,
Lefteris
If you are an engineer and you are not tired...
You are doing it wrong!
 

Offline helius

  • Super Contributor
  • ***
  • Posts: 2653
  • Country: us
Re: Initializing a struct member with a certain value if left undefined
« Reply #1 on: March 13, 2018, 07:18:22 am »
This is not straightforward to achieve in C, because data types don't have default values. What you can do is to start with a statically defined object that serves as a template, and return copies of it from your init() function. You could also do some macro hack like
Code: [Select]
#define NEWPWM { .Frequency=-1 }and require that it be used like
Code: [Select]
struct SimplePWM_Setup mysetup = NEWPWM;
mysetup.CCP_Module=42; //etc
« Last Edit: March 13, 2018, 07:19:58 am by helius »
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 3014
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: Initializing a struct member with a certain value if left undefined
« Reply #2 on: March 13, 2018, 07:29:49 am »
You are in need of C++. Try it  ;)

But, for normal C, I always start variables private to a module with an underscore (_) so that syntax prediction doesn't hint on it.

I have, on some occasions, played it dirty. Specifically to warn about illegal configurations or size errors of arrays using #error.
Code: [Select]
#if SimplePWM_Setup.frequency != -1
#error You're not supposed to initialize SimplePWM_Setup:frequency
#endif

Example:
Code: [Select]
typedef struct SimplePWM_Setup
{
    uint8_t CCP_Module;
    uint8_t Prescaler;
    uint16_t Max_Step;
    uint16_t Duty_Step;
    bool use_TMR4; // is a char
    uint8_t padding[3]; // useless space
    /* Private */
    int32_t _frequency;
};
You also need to learn about struct packing.
« Last Edit: March 13, 2018, 07:33:12 am by Jeroen3 »
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 7389
Re: Initializing a struct member with a certain value if left undefined
« Reply #3 on: March 13, 2018, 07:33:44 am »
Edit: CAUTION - SEE BELOW!

C does clear uninitialised variables by default.  If you replace the bool use_TMR4 flag with some bitfields, you could add an initialised flag, that is set by your Init function, so you can detect whether or not Init has been run, without increasing the size of the struct.   Also it makes little sense to have negative frequency, so once you have a separate flag, make it  uint32_t Frequency.

@Jeroen: The C preprocessor cant 'see' the value of C runtime variables or constants, so how is that #if going to do anything useful?
« Last Edit: March 13, 2018, 09:48:13 am by Ian.M »
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 3014
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: Initializing a struct member with a certain value if left undefined
« Reply #4 on: March 13, 2018, 07:42:31 am »
The preprocessor can see variables if set by literals. Not runtime, no.
 

Online glarsson

  • Frequent Contributor
  • **
  • Posts: 803
  • Country: se
Re: Initializing a struct member with a certain value if left undefined
« Reply #5 on: March 13, 2018, 07:59:32 am »
C does clear uninitialised variables by default.
No.  :palm:

Uninitialized variables are only set to all bits zero for variables with lifespan of the whole program, either declared at file scope (outside of a function) or inside a function and explicitly declared static using the reserved word 'static'.

Variables declared inside a function without 'static' will have random values in them (they will have bits and pieces of earlier variables and other stuff placed on the stack).

Variables whose memory are allocated using 'malloc', 'sbrk', etc will also have random content (except where otherwise noted, e.g. 'calloc').
 
The following users thanked this post: nugglix

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 7389
Re: Initializing a struct member with a certain value if left undefined
« Reply #6 on: March 13, 2018, 10:06:29 am »
Thank you for the correction.
Uninitialized variables are only set to all bits zero for variables with lifespan of the whole program, either declared at file scope (outside of a function) or inside a function and explicitly declared static using the reserved word 'static'.

Variables declared inside a function without 'static' will have random values in them (they will have bits and pieces of earlier variables and other stuff placed on the stack).
So its unfortunately *NOT* foolproof, and as XC8 is a C89 compiler that doesn't support the C99 .member= struct initialiser syntax you cant easily patch it by using Helius' idea above. :(

Quote
Variables whose memory are allocated using 'malloc', 'sbrk', etc will also have random content (except where otherwise noted, e.g. 'calloc').
malloc, etc. allocate MEMORY, not variables.  Also, XC8 doesn't implement malloc - it makes very little sense to do so on an 8 bit PIC!
 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #7 on: March 13, 2018, 11:56:12 am »
Code: [Select]
#if SimplePWM_Setup.frequency != -1
#error You're not supposed to initialize SimplePWM_Setup:frequency
#endif

Example:
Code: [Select]
typedef struct SimplePWM_Setup
{
    uint8_t CCP_Module;
    uint8_t Prescaler;
    uint16_t Max_Step;
    uint16_t Duty_Step;
    bool use_TMR4; // is a char
    uint8_t padding[3]; // useless space
    /* Private */
    int32_t _frequency;
};
You also need to learn about struct packing.

Does struct packing really matter on an 8bit? What you have there makes sense for a 32bit core but 8bit? Meh?
BTW I know this is off topic but it really sparked my curiosity, thanks for bringing it up!
If you are an engineer and you are not tired...
You are doing it wrong!
 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #8 on: March 13, 2018, 12:45:46 pm »
Edit: CAUTION - SEE BELOW!
Also it makes little sense to have negative frequency, so once you have a separate flag, make it  uint32_t Frequency.

It would actually make much more sense to use a float type, with low _XTAL frequencies you can achieve values in HZ or lower.
But I like to avoid including float math for something so simple. Not a great deal of people are going to use sub MHz on the main clock along with PWM.

What you are suggesting would make more sense with uint24_t for the frequency which is rather tempting but non standard.
On the other hand this library is indeed for use with PIC18F so it only needs to be microcontroller portable (which I can live without, as it complicates things and too much drama and no...)...

If you think about it a uint24_t can get the maximum value of 16777215 while the maximum theoretical frequency that can be achieved is 16MHz.
So you could say that if frequency is 0xFFFFFF then frequency is not set. It would also make for a slightly faster code if not also smaller but it doesn´t follow convention.
By convention a function would return -1 if it failed, same here to an extend. A negative number means you failed to initialize the frequency, but the idea is also that you are
always able to read the frequency. Or else I would just return the value of the frequency from the init function.
The problem comes though when you want to change the settings of the PWM. You got to run the Init function again! That doesn´t mean that the Init function will succeed though!
If it fails, you are stuck with the old frequency, which you would have no way of knowing in your runtime unless you had stored it.

So that´s the mentality behind building this library, it´s very gui friendly, doesn´t need to be in my specific occasion, never the less as we say here in Greece,
sensible parents' kids cook before they get hungry  :P

Cheers,
Lefteris
If you are an engineer and you are not tired...
You are doing it wrong!
 

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 11764
  • Country: gb
    • Mike's Electric Stuff
Re: Initializing a struct member with a certain value if left undefined
« Reply #9 on: March 13, 2018, 12:56:44 pm »


It would actually make much more sense to use a float type, with low _XTAL frequencies you can achieve values in HZ or lower.

Unless you were already using floats elsewhere, that would be insane as it would pull lots of floating point library code in.
It rarely makes sense to use FP in an embedded system, as real-world values rarely have the range that would need floating point
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Online filssavi

  • Regular Contributor
  • *
  • Posts: 229
Re: Initializing a struct member with a certain value if left undefined
« Reply #10 on: March 13, 2018, 01:10:15 pm »
It rarely makes sense to use FP in an embedded system, as real-world values rarely have the range that would need floating point

I disagree, sort of...

While it’s true that very rarely you need FP in embedded systems, they come in really really handy in certain tasks like for example motor drives in particular and control loops more in general since the alternative (Fixed point) is really really painful to work with and there are a lot of pitfalls and possible errors to do with underflow/overflow and you have to keep track of conversion constants which often makes your head hurt just to think about it

The only caveat is that for FP to be viable you need an FPU, that means a largish, more expensive, MCU, and that is why Fixed point is still widely used in lower cost motor drives (whaling machines for example)
 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #11 on: March 13, 2018, 01:18:57 pm »
But of course Master I speak of no blasphemy! (Say that to the Arduino guys :P )
If you are an engineer and you are not tired...
You are doing it wrong!
 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #12 on: March 13, 2018, 01:24:51 pm »
It rarely makes sense to use FP in an embedded system, as real-world values rarely have the range that would need floating point

I disagree, sort of...

While it’s true that very rarely you need FP in embedded systems, they come in really really handy in certain tasks like for example motor drives in particular and control loops more in general since the alternative (Fixed point) is really really painful to work with and there are a lot of pitfalls and possible errors to do with underflow/overflow and you have to keep track of conversion constants which often makes your head hurt just to think about it

The only caveat is that for FP to be viable you need an FPU, that means a largish, more expensive, MCU, and that is why Fixed point is still widely used in lower cost motor drives (whaling machines for example)

I disagree strongly... With floating point math there is no way to predict error when you values get near the limit, but with fixed point you can always work your way with windup delimiters.
If you are an engineer and you are not tired...
You are doing it wrong!
 

Online filssavi

  • Regular Contributor
  • *
  • Posts: 229
Re: Initializing a struct member with a certain value if left undefined
« Reply #13 on: March 13, 2018, 02:27:04 pm »
I disagree strongly... With floating point math there is no way to predict error when you values get near the limit, but with fixed point you can always work your way with windup delimiters.

Again you are right in absolute terms but if we think about this specific case the worst case scenario in a traditional motor drive is on the current loop

Current can vary (being generous) 4 orders of magnitude (lets say from hundreds of mA to hundreds of A) at one extreme of the range 999.999A we can find that the error due to conversion is 0.000023.. (2.3*10^-5) while at the other end at 1mA the error due  to conversion is 4.7e-11.

now even if your current sensing ADC has a 16 bits (which is very very very unlikely, 12 bit is already uncommon 8 bit is more likely) your conversion error is 2 orders of magnitude less than an LSB
moreover do you really think you can even control a motor's current to the milliampere level when you are pumping 900A, and even if you could do you think that your  motor's torque would really change?

now you have to take into account compound error but than again I can't think of any application in motor control where you have iterative calculations that can lead to significant compound errors

so wrapping up while true that errors in floating point do exist and can be dangerous, in this particular application in a narrow field of mathematics/engineering they can be safely discarded

proof and point most modern (ok except for the very cheapest product lines) DSP's specifically targeted to motor control have an FPU, if it was that useless/dangerous they would have put all that silicon to another use
 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #14 on: March 13, 2018, 02:43:04 pm »
Hmmm yes anything Phase controlled can greatly benefit from a dedicated FPU, that´s why there is one. That´s though more for the phase control itself rather than anything else. To use with the trig functions.
But motor control for Permanent Magnet DC Motors for example, meh... you won´t need more than an 8bit.
You´ll never need so much fine control in the current department for motors. But I digress... we are totally off-topic :P
If you are an engineer and you are not tired...
You are doing it wrong!
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 1755
  • Country: nz
Re: Initializing a struct member with a certain value if left undefined
« Reply #15 on: March 13, 2018, 03:41:59 pm »
I am using a struct to interface with a library I am writing, I want that if the user doesn´t initialize a member of the struct (which he/she is not supposed to initialize but rather only read as information available at anytime to him/her) for that member to default to a certain value.

I've seen two approaches
- use a 'mask' field to indicate which values have been populated.
- have a "initialize" or "setDefaults" function that defaults values for the structure

Code: [Select]
   struct Foo foo;
   FooSetDefaults(&foo);
   foo.whatever = value1;
   foo.somethingElse = value2;
   FooDoSomething (&foo);

You can always add a 'hidden' magic number in the structure, which you set in SetDefaults(), so you can test if the structure has been properly initialized.

Maybe it is better to completely hide the structure from the user, and just use a pointer? That way the user is not made aware of the implementation at all, and you can change your backend implementation on a whim, just as long as the API is kept the same.

Code: [Select]
   struct Foo *foo;
   foo = FooNew();
   FooSetWhatever(foo, value1);
   FooSetSomethingElse(foo, value2)
   FooDoSomething(foo);
   FooFree(foo);

But that is just inviting memory leaks when you forget to call FooFree();
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 3014
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: Initializing a struct member with a certain value if left undefined
« Reply #16 on: March 13, 2018, 06:19:10 pm »
Maybe it is better to completely hide the structure from the user, and just use a pointer?
Hmm... You can leverage casting struct pointers and have the user view a different struct then private to the module. But still work with the same block of memory.
Code: [Select]
typedef struct ModulePublic {
    int userParam1;
    int userParam2;
    int userParam3;
    unsigned char _alloc_private[8];
};

typedef struct ModulePrivate {
    int userParam1;
    int userParam2;
    int userParam3;
    int privateStuff1;
    int privateStuff2;
};
 

Offline David Chamberlain

  • Regular Contributor
  • *
  • Posts: 232
Re: Initializing a struct member with a certain value if left undefined
« Reply #17 on: March 13, 2018, 06:36:27 pm »
Going to agree with hamster_nz here on his solution, I've used both approaches many times myself.



 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #18 on: March 14, 2018, 05:43:10 am »
I am using a struct to interface with a library I am writing, I want that if the user doesn´t initialize a member of the struct (which he/she is not supposed to initialize but rather only read as information available at anytime to him/her) for that member to default to a certain value.
I've seen two approaches
- use a 'mask' field to indicate which values have been populated.
- have a "initialize" or "setDefaults" function that defaults values for the structure

One thing is that I can not allocate memory, it´s just not supported on 8bit PICs, or else I would have used a macro by that time.

The problem with the setDefaults function is that it has to be run in the runtime, it has to be included in an one time init function.
That´s what I want to avoid or at least hide.

Maybe it is better to completely hide the structure from the user, and just use a pointer? That way the user is not made aware of the implementation at all, and you can change your backend implementation on a whim, just as long as the API is kept the same.

Anyhow I have to use pointers cause there is no other way for a function to alter a variable in the function from the main, other than the value returned.

I´ve been looking into it for some time and yes I am in need of C++ indeed, but for now you only get the XC8 which is a C89 compiler so touph luck for me.
I will have to find another work around or maybe just leave it as it is. We´ll see.

Thanks for the help and the ideas so far!
Cheers,
Lefteris
If you are an engineer and you are not tired...
You are doing it wrong!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 7389
Re: Initializing a struct member with a certain value if left undefined
« Reply #19 on: March 14, 2018, 05:57:54 am »
Hmm.

What about an array of static (file scope) structs in the same file as access functions for them?   Pass in a #define at build time for the number of SimplePWMs to support - either as a compiler command line -D define or as a user supplied include file, and rely on the C startup code zeroing them to detect use before initialisation.  The only interface exposed would be the access functions declared in the associated header.
 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #20 on: March 14, 2018, 06:26:33 am »
It´s really becoming a headache at this point though.

As far as I know all variables are initialized as zeros when first called in C. So from this perspective trying to pass the structure without initializing
the values which effect the frequency value will change the frequency value and the init will fail. This is all made in the init implementation.

The only thing to do is to actually include a first init made flag, nothing else. Also turn the bool value that I use to a bitfield to conserve a bit of RAM,
but you pay it in the program space as bit checks are required. These are all but small trade offs that should be made. Can´t really find a better solution.

For the moment I think that I can live with that.
If you are an engineer and you are not tired...
You are doing it wrong!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 7389
Re: Initializing a struct member with a certain value if left undefined
« Reply #21 on: March 14, 2018, 06:39:02 am »
As far as I know all variables are initialized as zeros when first called in C.
As Glarsson pointed out earlier, that isn't true of auto (function or block scope) variables, so the *ONLY* way of guaranteeing that in the face of user idiocy is to not let the user declare their own copies of the struct, hence my advise to use an array of static (file scope) structs declared in a source library .c file. 

That still doesn't help you if the user does something really dumb like disabling zeroing uninitialised variables 'to speed it up', but if the user's that wilfully *STUPID*, there is little you can do except run away as far as possible - stealthily and quickly - to avoid being sucked into the resulting clusterf**k.

Incidentally, there is a third party C++ compiler for 8 bit PICs (excluding baseline parts) - check out http://www.sourceboost.com/Products/BoostCpp/Overview.html

However its quite a long way from HiTech PICC / Microchip XC8 syntax and due to its small market penetration compared to XC8, using it would decrease the target audience for your library considerably.
« Last Edit: March 14, 2018, 07:03:56 am by Ian.M »
 

Offline David Chamberlain

  • Regular Contributor
  • *
  • Posts: 232
Re: Initializing a struct member with a certain value if left undefined
« Reply #22 on: March 14, 2018, 06:40:13 am »
As far as I know all variables are initialized as zeros when first called in C.

No - https://stackoverflow.com/questions/21152138/local-variable-initialized-to-zero-in-c

and even if it did double no, never rely on a compiler to initialize memory for you.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 3014
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: Initializing a struct member with a certain value if left undefined
« Reply #23 on: March 14, 2018, 06:54:18 am »
As far as I know all variables are initialized as zeros when first called in C. .
Quote from: ISO/IEC 9899:TC3 6.7.8:10 (old one, I know)
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. If an object that has static storage duration is not initialized explicitly,
then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these
rules.
Quote from: 6.2.4:1
An object whose identifier is declared with external or internal linkage, or with the
storage-class specifier static has static storage duration. Its lifetime is the entire
execution of the program and its stored value is initialized only once, prior to program
startup.

So yes, for statics and globals. Some linkers offer to zero initialize all memory, but this means inserting a loop that must run before main() is entered.
However, always explicitly initialize variables. Since this is one of the easiest things for implicit bugs to crawl in.
I crushed one just today, since some compilers, especially those for 8 bit, do not honor all parts of the C standard. Such as this one, adding unnecessary loops and start delay.
Quote from: misra Rule 9.1 (required)
All automatic variables shall have been assigned a value before being used.
« Last Edit: March 14, 2018, 06:56:51 am by Jeroen3 »
 

Offline TrickyNekro

  • Regular Contributor
  • *
  • Posts: 167
  • Country: gr
  • Drinking Frappé on the way to Isomnia!
    • Youtube channel, electronics and more ;-)
Re: Initializing a struct member with a certain value if left undefined
« Reply #24 on: March 14, 2018, 06:59:27 am »
As far as I know all variables are initialized as zeros when first called in C.
As Glarsson pointed out earlier, that isn't true of auto (function or block scope) variables, so the *ONLY* way of guaranteeing that in the face of PEBKAC grade idiocy is to not let the user declare their own copies of the struct, hence my advise to use an array of static (file scope) structs declared in a source library .c file.

The struct is initialized in main and then the pointer of the struct is send to the function, it´s not initialized in the function, I really wouldn´t do that :P

Still your idea is not bad. It doesn´t have to be an array, a single struct can suffice. Then the user can always take the risk to call their own struct of the same type.
Yeah, dunno that´s something to think of.
If you are an engineer and you are not tired...
You are doing it wrong!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf