struct pointer

Go To Last Post
22 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello

i'm trying to make my struct to be accessible in all files of the project, but it doesn't seem to work. A simple example

file for declarations

#ifndef INCFILE1_H_
#define INCFILE1_H_

#include 
#include 

extern struct mine{
	uint8_t ip;
	uint8_t h1;
	uint8_t h2;
	uint8_t min1;
	uint8_t min2;
	uint8_t sec1;
	uint8_t sec2;
	uint8_t mode;	
};

void bbb(void);

#endif /* INCFILE1_H_ */

main file

#include "IncFile1.h"
#include 

struct mine *mp;

int main(void)
{
    while(1)
    {
        //TODO:: Please write your application code 
    }
}

and CFile.c

#include "IncFile1.h"

void bbb(void)
{
	mp->mode = 10;
}

when i compile it, i get

Quote:
Error 2 'mp' undeclared (first use in this function) C:\Users\Gytis\Documents\Atmel Studio\struct_band\struct_band\CFile1.c 11 2 struct1

Anybody could help?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Personally I'd use a typedef:

#ifndef INCFILE1_H_
#define INCFILE1_H_

#include 
#include 

typedef struct {
   uint8_t ip;
   uint8_t h1;
   uint8_t h2;
   uint8_t min1;
   uint8_t min2;
   uint8_t sec1;
   uint8_t sec2;
   uint8_t mode;   
} mine_type;

extern mine_type mine;

void bbb(void);

#endif /* INCFILE1_H_ */ 
#include "IncFile1.h"
#include 

mine_type mine;

int main(void)
{
    while(1)
    {
        //TODO:: Please write your application code
    }
} 
#include "IncFile1.h"

void bbb(void)
{
   mine.mode = 10;
} 

However I think a "better" solution is, as you suggest to pass a struct pointer. That is:

#ifndef INCFILE1_H_
#define INCFILE1_H_

#include 
#include 

typedef struct {
	uint8_t ip;
	uint8_t h1;
	uint8_t h2;
	uint8_t min1;
	uint8_t min2;
	uint8_t sec1;
	uint8_t sec2;
	uint8_t mode;
} mine_type;

void bbb(mine_type * mp);

#endif /* INCFILE1_H_ */
#include "incfile.h"
#include 

mine_type mine;

int main(void)
{
	bbb(&mine);
	while(1)
	{
		//TODO:: Please write your application code
	}
}
#include "incfile.h"

void bbb(mine_type * mp)
{
	mp->mode = 10;
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I compiled the example with typedefing, works great, thanks. The surprise for me was that i was assuming that syntax for global variables and pointers in this case should be similar, because of the similarity of their use. I sort of took example for global variables and modified it to the pointer to the struct, because i thought pointers should be used over globals. So maybe this is the case where it is vice versa?
p.s. i don't want to pass pointer as function parameter.

Last Edited: Wed. Feb 27, 2013 - 06:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well if you want bbb() to use a global struct pointer with out being passed a pointer:

#ifndef INCFILE1_H_
#define INCFILE1_H_

#include 
#include 

typedef struct {
	uint8_t ip;
	uint8_t h1;
	uint8_t h2;
	uint8_t min1;
	uint8_t min2;
	uint8_t sec1;
	uint8_t sec2;
	uint8_t mode;
} mine_type;

extern mine_type * mp;

void bbb(void);

#endif /* INCFILE1_H_ */
#include "incfile.h"
#include 

mine_type mine;
mine_type * mp = &mine;

int main(void)
{
	bbb();
	while(1)
	{
		//TODO:: Please write your application code
	}
}
#include "incfile.h"

void bbb(void)
{
	mp->mode = 10;
}

as you can see this is close to where you started but you made the classic error. You defined:

struct mine *mp; 

and that created a global struct pointer but it did not actually allocate any space for an example of the struct itself and it did not initialise the pointer to actually point at such a thing either. Later you used:

	mp->mode = 10;

but mp had never been assigned a value (so, because of being global) would have held 0 and this is THE CLASSIC programming error of accessing a null pointer.

Now my code not only creates the pointer (admittedly now using a typedef):

mine_type * mp = &mine;

but it also creates an example of the structure:

mine_type mine;

and as you can see mp was assigned the address of it.

Another way to do this (quite like C++ in fact) would be to do:

mine_type * mp = (mine_type *)malloc(sizeof(*mp));

The malloc would create the storage for the struct and the address of that storage would be returned from malloc() and assigned to the pointer.

However mallo() is best avoided in embedded systems and just creating an example of the struct:

mine_type mine;

is probably preferred.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks,

I've long been puzzled/confused about how to do this sort of thing.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jim,

Just a word of caution: what OP is asking for is a bad idea. I've showed him how to do it but the only time you really want to have things globally visible is when you have no choice. Like an ISR() that has void input/output needs to share access with a struct used in the main() line code. The ISR() can only get access if it is global or else it would have to call a function to get a reference to the struct and that would be "costly".

The version I showed above with a struct pointer being passed into bbb() is the closest to a "good" solution I've shown. So don't take too much away from the rest.

I think a lot of people's reluctance to pass round pointers of whatever stems from it possibly being quite complex but that's where typedef's come into their own. You make a really complex definition in just one place:

typedef struct {
  int n;
  char msg[10];
} packet_type_a;

typedef struct {
  float f;
  long coords[4];
  packet_type_a packeta;
} packet_type_b;

typedef struct {
  int values[5];
  short s;
  packet_type_b packets[14];
} foo_type;

then elsewhere it's easy to work with "foo_type":

foo_type foo;

int main(void) {
  bar(&foo);
}

void bar(foo_type * fp) {
  fp->packets[5].packeta.n = 12345;
}

So it's surprisingly easy to pass round really complex things once you have your foo_type defined using a typedef.

(this was an extreme example just to show how much "rubbish" a simple thing like "foo_type" can mop up).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I've showed him how to do it but the only time you really want to have things globally visible is when you have no choice.

Well, I'll tend to disagree--for real MICROcontroller apps.

Now, all of the below is IME. And indeed, as the app gets bigger I tend to add more structure and "data hiding" and the like.

1) Let's start with that--"data hiding". Exactly who/what are we hiding it from? This is an AVR8, not a Windows PC.
2) Many apps are in the Tiny/Mega48/Mega88 range. There are many here that only play with "big iron". "Start with a [insert flavour of choice here--Mega1284; Mega128; Mega328], the biggest in the family; you can always use a smaller micro later." Not my approach.
3) IME there are a few guidelines for making tight apps for these MICROcontroller models:
3a) Use nearly all global data--unless there is an advantage to not doing so.
3b) Do everything in main() that you can--unless there is an advantage not to.
3c) Have global (and/or local to main() ) register-based scratchpad variables and use the heck out of them.

Note that the above does >>not<< mean to not use pointers. E.g. if there is an advantage to have a struct for each channel, then the processing can use the pointer into the array of those structs representing the "current channel". >>If<< there is an advantage.

I realize that all this is heretical and will probably not allow me to win the papal election next month.

-- IME the bigger the base processor, the more structure and data hiding.
-- As a corollary to that, the smaller apps tend to be one-person dev team. The more people the more structure is warranted.

An example from my experience is a Modbus RTU slave driver that we developed. A piece of AVR art. Fully configurable; hardware-abstraction layer; data hiding. The whole bit. Used in several Mega32 and Mega64 apps.

But it practically consumes an entire Mega8. Basically unusable for a MICROcontroller app. A day's work removing the layers results in a mini-driver that is usable on a Mega48 (if you have limited max message length) as it takes about half the flash.

YMMV. Good luck to all you MISRA-able 'Freaks.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lee you may well be right I've been having a MISRAble time lately and it's tainting my thinking.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for this discussion.

Enlightening, to be sure.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well I am about 25,000 posts behind theusch above but don't agree.....

I find that many good programming practices can be used even on small processors (<= mega16).

there will always be exceptions and good judgment is always required.

Some thought up front and some prototyping will let you test your assumptions and design approach so that the bad news is not all found at the end (which turns out not to be the end)

The end story might be like what theusch described.... but not necessarily.

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have often wondered about data hiding/protection.

In a desktop app, we can make the scope of a variable local to a function, and be quite confident that the application will not change it. Seems like a good protection mechanism.

But, in a microcontroller with a stack that can run amok, anything can be modified by anything. Seems like a local variable would be protected from accidental accesses, but not the BIG OOOPSIE kind of things.

Maybe this is better than nothing. Hope I am not opening the floodgates to a Holy War here; that is not intended. Is there any consensus? Or, de we agree to disagree without being disagreeable?

Thanks
JIm

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh Yes, bring it on. It's a great bulk of information already and it just keeps getting better.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you exhaust the stack, there is nothing that can save you no matter what your platform is.

It is easier to run out of stack on small systems like those run by AVRs, but you can certainly do it on any system.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But, in a microcontroller with a stack that can run amok, anything can be modified by anything. Seems like a local variable would be protected from accidental accesses, but not the BIG OOOPSIE kind of things.

This can happen just as easy in a desktop app. E.g. if the app is written in C you have about the same amount of rope to hang yourself as in an embedded application.

Things become somewhat more safe in languages that does not (generally) allow things like uninitiated pointers, or even pointers at all, e.g. Java and C#.

It's been a good 10 or so years ago since I last tried this (sketchy)

typedef void (foo *)(void);

int main (int argc, char *argv[])
{
   foo = 0;
   foo();
   return 0;
}

on a Windows system and the result was disatrous.

Likewise, something like

void bar(void)
{
   char foo[5];
   strcpy(foo, "ABCDEFGHIJKLMNOPQRSTUVXYZ1234567890abcdefghijklmnopqrstuvxyz");
}

int main (int argc, char *argv[])
{
   bar();
   return 0;
}

should create a certified mess.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I have often wondered about data hiding/protection.

Well one of the protections of data hiding is simply keeping control of the code in one obvious place. I know this example is a bit extreme but:

// adc.c
int adc_multiplier = 31;

int read_ADC(void) {
  // make ADC reading
  return ADC * adc_multiplier;
}
// spi.c
void init_SPI(void) {
  // other stuff
  adc_multipler += 2;
}

If adc_multiplier is not local to the function where it is used or at least static within the adc.c file then maybe as a test when you were working on the SPI stuff you tried out that line to just tweak the multiplier and later forgot to remove that piece of test code. Really this variable has no business being exposed in a wider area than it's really used.

I know the arguments for the fact that AVR apps are generally so small that you'll only ever have one engineer working on them and they ought to know what they are doing with all their variables. I guess that's true but even in a complex one many project things can get a bit "all over the place" if you don't impose at least a bit of structure to what you do.

It's kind of a shame that the MISRA rules are not open (you have to pay to get a copy) because a lot of what they mandate is just plain common sense. I know I'll probably be killed for revealing this but even rule 14.8 shows a generally good idea:

Quote:
Violates MISRA 2004 Required Rule 14.8, left brace expected for while, do...while and for

(that from something I'm currently working on to clear MISRA lint).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess that I don't understand typedef very well. I don't think I have ever used that construction. Why would one use it? I think I remember being told, in the one C class I have taken, that it was a hiding or protection mechanism. Obviously, there is more, but I don't understand what.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Why would one use it?

For the very reason I showed above.

Here's another example. First without using a typedef:

int (*fn_ptr)((char, long, short, int);

int main(void) {
  fn_ptr = int(*)(char, long, short, int) 0x1234;
  val = fn_ptr('A', 0xDEADBEEF, 1234, 32323);
}

and with:

typedef int (*fp_type)((char, long, short, int);
fp_type fn_ptr;

int main(void) {
  fn_ptr = (fp_type)0x1234;
  val = fn_ptr('A', 0xDEADBEEF, 1234, 32323);
}

The real advantage here is if the interface to the function is now changed to (int [], char*, long, long) then it only needs to be changed in the typedef.

In other words typedef has added a new type to C (like char, int, long, etc) which can be given a meaningful (short!) name and then used wherever you need such a type definition.

To be honest, with my packet_a/packet_b example above I don't know how you could do it without a typedef, how could you specify the following so it worked:

void bar(foo_type * fp) {
  fp->packets[5].packeta.n = 12345;
} 

You could replace "foo_type *" in this with "void *" which allows you to pass a pointer to anything. But how could you then cast "fp" to make the ->packets[5].packeta.n access would certainly blow my brain apart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Even AVR applications can sometimes benefit unit testing.
Data hiding can reduce the size of a unit.
A smaller unit can make for a simpler test and make it more likely that said unit can be tested on other platforms.
Small units requiring only small thoughts are easier to maintain than big units reuiring big thoughts.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Small units requiring only small thoughts are easier to maintain than big units reuiring big thoughts.

I like that formulation, and will likely steal it and use it as my own! :D

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Quote:

Small units requiring only small thoughts are easier to maintain than big units reuiring big thoughts.

I like that formulation, and will likely steal it and use it as my own! :D
Be sure to mind my q's and q's.

Iluvatar is the better part of Valar.