pointers, functions, bit fields, reference, struct..

well, as you can see from the title, I need to put together some of the most odd and obscure features of C. i have this structure containing some settings:

typedef struct
{
  unsigned int channel  : 4;
  unsigned int octave    : 4;
  unsigned int sens     : 1;
  unsigned int patch    : 7;
  unsigned int waveform : 3;
  unsigned int threshold : 9;
  unsigned int tone    : 4;
}Settings;

and i want to be able to change them using my menu-driven display and a "multipurpose function" that, called with those variables (obviously given by reference and not by value), can show and edit them, instead of writing the same code tons of time. here's a little effort (the parts between /**/ comments are the pieces of code i wansn't able to write):

void editSetting(char *str, /* don't know what to put here */)
{
  /* storing the old value */
  
  byte state = IDLE;       //variable containing the status of my keypad
  byte save = 255;          // 255=do nothing    1=save and exit    0=exit only
  lcd.setCursor(0, 1);
  lcd.print(str);              //the function also accepts and writes a string used as a description
  lcd.setCursor(9, 2);
  
  while(save != 255)
  {
    state = buttonCheck(A0)
    switch(state)
    {
      case UP:   /* increments the variable */
                 break;
                 
      case DOWN: /* decrements the variable */
                 break;
                 
      case SEL:  save = 1;
                 break;
                 
      case BACK: save = 0;
                 break;
    }
    if(state==SEL || state== BACK)
      break;
    lcd.print(/*variable*/);
  }
  if(state == SEL)
    /*just quit*/
  if(state == back)
    /*reset the variable to the old value saved before and then quit*/
}

hope i was clear, and thanks in advance for your help!

If it was my application, the first thing that I would do is evaluate that structure.

  unsigned int channel  : 4;

You want to use half the storage that an unsigned int allocates, to hold a value. Hmmm, looks like a byte to me, and no reason to mess with bit fields.

  unsigned int octave    : 4;

Ditto.

  unsigned int tone    : 4;

Ditto.

Now the order of the fields in the structure doesn't really matter, does it? So, put all the byte values first.

Then, with the struct as defined, use sizeof() on an instance, and see what size the struct is. Then, get rid of the bit field stuff, and see what the new size is. Does the use of the bit field stuff make a significant difference in the size of the struct instances?

How many instances are there going to be?

void editSetting(char str, / don't know what to put here */)

And if you don't give us some idea what is supposed to go there, we don't either.

    state = buttonCheck(A0)

is missing a ;

case UP: /* increments the variable */

Increments what variable?

case DOWN: /* decrements the variable */

Decrements what variable?

lcd.print(/variable/);

Print what variable? You can't print a whole struct instance, if that is what you are thinking.

hope i was clear

No, sorry, you weren't.

I need to put together some of the most odd and obscure features of C.

None of these is obscure or odd, and any good C reference or tutorial will tell you all you need to know.

PaulS:
If it was my application, the first thing that I would do is evaluate that structure.

  unsigned int channel  : 4;

You want to use half the storage that an unsigned int allocates, to hold a value. Hmmm, looks like a byte to me, and no reason to mess with bit fields.

That is not right.

An int is 16 bits, that field only allocates 4 bits.

Integral types <-> bit fields
14 bytes <-> 4 bytes

The bit field is clearly smaller.

The problem with bit-fields is that they may look like a neat way of mapping structures onto hardware registers or message formats, they're frequently not portable, because of endianness or memory alignment.

I guess an enum and a switch/case could do the job.

Decrements what variable?

struct member perhaps ?

An BTW, why do you pass a string as first argument ?

void editSetting(char *str, /* don't know what to put here */)

PaulS:
If it was my application, the first thing that I would do is evaluate that structure.

  unsigned int channel  : 4;

You want to use half the storage that an unsigned int allocates, to hold a value. Hmmm, looks like a byte to me, and no reason to mess with bit fields.
...

Paul, i think you're confusing nibbles (4bits) with bytes (8bits). believe me, it would have been nice if I had enough memory to do not mess with bit fields. my struct=32bits=8bytes. allocating all variables as int=7variables * 2bytes (int size) = 14bytes. i will have 3 user-selettable sets of settings, so 83=24bytes against 143=42.

AWOL:

I need to put together some of the most odd and obscure features of C.

None of these is obscure or odd, and any good C reference or tutorial will tell you all you need to know.

i meant, they're obscure or odd to me :slight_smile:

AWOL:
The problem with bit-fields is that they may look like a neat way of mapping structures onto hardware registers or message formats, they're frequently not portable, because of endianness or memory alignment.

i think (even if the proper word is "hope") that memory alignment is not affected by my struct, because it is made to allocate exactly 4 bytes (as if it was a long integer)

mromani:
An BTW, why do you pass a string as first argument ?

void editSetting(char *str, /* don't know what to put here */)

BTWs (and solutions as well) are welcomed! it's because i want the function to manage the display as well, so that string is what it will print. the use of this function to manage ALL the user-made parameter changes will ensure consistency among all the menu sections.

Until you know the correct amount of bits in a byte, You need to steer clear of bitfields.

32 bits is ony 4 bytes, not 8.

You need to re-consider the alignment statement you posted.

Here is a handy paragraph

c99 - Bit Fields.
An implementation may allocate any addressable storage unit large enough to hold a bitfield.
If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit.
If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.
The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined.
The alignment of the addressable storage unit is unspecified.

Also note that the standard says that a "bit-field shall have a type that is a qualified or unqualified
version of int, unsigned int, or signed int", so having a bit-field in a char type is non-standard.

This explicitly makes bit-fields non portable, not even slightly.

Arduino is perfect for bit fields as they work on a 1 byte address boundary. But do not use the bit field with out extensive testing.

A standard class' data members are placed in memory in the order they are listed, a bit field can be backwards and there is no way to force its MSB/LSB ordering.

However by allocating contiguous memory using a 32 bit integer
then casting to your bit field ensures the bit field is mapped to memory.

Paul, i think you're confusing nibbles (4bits) with bytes (8bits).

Yes, I got the size wrong. Pre-coffee answers are not always the best.

pYro_65:
Until you know the correct amount of bits in a byte, You need to steer clear of bitfields.

32 bits is ony 4 bytes, not 8.

You need to re-consider the alignment statement you posted.

never said neither that 32 bits equals 8 bytes nor that my sketch has to be portable, since every arduino uses 1-byte adresses, doesn't it?

however, i forgot to explain that the main goal by now it to get the function to work passing any of the setting variable (or any othere, already said that i will use this function very often in this project) by reference.

my struct=32bits=8bytes

Is this not saying 32bits = 8 bytes, which is wrong.

Bitfield members are non-addressable. You cannot pass a member by reference. you will get 'Unable to bind" errors. You will have to pass the entire structure by reference then access the member directly.

pYro_65:

my struct=32bits=8bytes

Is this not saying 32bits = 8 bytes, which is wrong.

Bitfield members are non-addressable. You cannot pass a member by reference. you will get 'Unable to bind" errors. You will have to pass the entire structure by reference then access the member directly.

oh, you're right, it was just silly mistake. however, with the right calculations we'll have 12bytes against 42, that is even a wider ratio to justify an eventual adoption of bit fields.

pYro_65:
This explicitly makes bit-fields non portable, not even slightly.

If bit fields were portable, they wouldn't be useful. It's precisely because they aren't portable -- meaning, don't have an abstract machine defined behavior -- that they are so useful.