Jump to content

Passing arrays as parameters?


wackazong
 Share

Recommended Posts

Hi!

Another thing that occured to me today: Is it possible/recommended to pass arrays as function parameters? I defined a struct like:

typedef union {
	struct {
		unsigned char RED;
		unsigned char GREEN;
		unsigned char BLUE;
	};
	struct {
		unsigned char COLOR[3];
	};
} led_color_t;

This way, if I pass this variable to a function, lets say void SetColor(led_color_t color); I can go through the three colors in a loop (color[0], color[1], color[2]), and do not have to adress them each on their own in the code. Is that a bright thing to do? If I try, I get a compiler warning: structure '_color' passed as function argument changed to pointer

It seems that a pointer is passed instead of the variable, and it seems that this could be inefficient code. But actually I have no idea. Does anybody know whether this is recommended? I till stick to passing three unsigned chars red, green, blue until I know whether passing the array is a good idea.

Thanks, ALEXander.

Link to comment
Share on other sites

You might want to post more details showing your function and how you are calling it.  It'll help people correct your specific error.  But that said, I think I can provide some help here.

I can think of very very few cases with structures where you would ever want to pass them by value.  The main reason you'd want to pass a struct by value would be if you wanted to modify the values without modifying the original structure values, but there are better ways to accomplish this even when you'd passes a pointer to the struct.  Whenever you make a function call, the compiler must create assembly code which pushes your function parameters on a stack, then the function being called must pop them off of a stack.  The more parameters, the more data-pushing-and-popping code needs to be create, and the more stack is consumed.  When taken to extremes, this can equal a slow and inefficient app.

When you pass a pointer to a structure, it is often smaller than the structure, because structures often contain multiple items.  I believe on the PIC's used here that pointers are 3 bytes?  Anyway, it boils down that passing pointers to structure is most likely the best way to pass a struct and will result in more efficient code.

So, your function should be defined like this:

  void SetColor(led_color_t * p_color);

This is not a multiplication :-)  The * is letting the compiler know that the variable is a pointer.

then you can access the elements of the struct using:

  p_color->COLOR[x]

or..

  p_color->RED

  p_color->GREEN

  p_color->BLUE

Link to comment
Share on other sites

hi alexander,

first you have to know that an array variable in C is nothing else than a pointer to the

data of the array. if you address an element in the array, the compiler just shifts this

pointer according to the field size. It's just a smarter way of dereferencing a pointer.

the compiler also knows the field type and can handle it accordingly then.

compiler warning: structure '_color' passed as function argument changed to pointer

I think this happens:

because you have a union, there are two possibilities for the compiler to handle

the passing of your var to the function: as three-bytes-data or as an array variable,

which is a pointer.

the optimizer finds that you just use the array type in your function and decides

to pass it as a pointer, which makes sense because less data will be put on the

function stack.

In my eyes this is just an optimazation hint, and nothing is wrong

with your code.

as long as you just read the data, there is no problem with that.

If you would write, you would just change the original data, because your

array var is a pointer to the data. It's a bit weired in conjunctin with the

union thing, e.g. what would happen if you do both in the function, writing

to the single fields and the array fields? maybe then the compiler would copy

the data, and the array-dereference would point to the copied data then?

there are other optimizations like this, which will cause the compiler to throw

a warning:

8.1.5    Loop Reversing

This optimization is done to reduce the overhead of checking loop boundaries for every iteration. Some simple

loops can be reversed and implemented using a “decrement and jump if not zero†instruction. SDCC checks for

the following criterion to determine if a loop is reversible (note: more sophisticated compilers use data-dependency

analysis to make this determination, SDCC uses a more simple minded analysis).

    • The ’for’ loop is of the form

      for(<symbol> = <expression>; <sym> [< | <=] <expression>; [<sym>++ | <sym> += 1])

      <for body>

    • The <for body> does not contain “continue†or ’breakâ€.

    • All goto’s are contained within the loop.

    • No function calls within the loop.

    • The loop control variable <sym> is not assigned any value within the loop

    • The loop control variable does NOT participate in any arithmetic operation within the loop.

    • There are NO switch statements in the loop.

this is from the sdcc manual (I attached it to the post).

I also found this about passing arrays to functions in c++:

http://www.itee.uq.edu.au/~comp2303/Leslie_C_ref/C/SYNTAX/functions.html

I believe that passing arrays as data to functions is not part the concept of C, because function

parameters will be hold on the the stack, which is limited. so for bigger data amounts you would

pass a pointer anyway.

I think I should study this passing issue a bit deeper too.

correction: by default sdcc does not push the params/vars in a function to the stack.

therefore functions are by default non-reentrant. to write a function that you can call recursively, you need to declare

the function with the keyword __reentrant (sdcc manual 3.7 Parameters & local variables). also check

chapter 8.2 ANSI Compliance.

sdccman.pdf

Link to comment
Share on other sites

It seems that a pointer is passed instead of the variable,

You win!

It's in sdcc's manual (attached to the above post, downloadable from the website), and yes, all aggregates are passed as pointers in SDCC. When you use them in the function, this works out OK because the pointer still goes to the same data. I fell asleep while typing this, and the guys already did all the C-specifics, enjoy :)

Link to comment
Share on other sites

It's in sdcc's manual (attached to the above post, downloadable from the website), and yes, all aggregates are passed as pointers in SDCC.

I'dont know which part of the sdcc manual stryd_one is referencing, but I found some interesting stuff about

functions / parameters / structures in the manual's chapter '8.2 ANSI-Compliance':

• structures and unions cannot be assigned values directly, cannot be passed as function parameters or assigned

  to each other and cannot be a return value from a function...

so if you want to pass a structure variable to a function, it's only correct to declare it as a pointer (as Narwhal said), and copy the struct manually field by field if you need to work with a local copy of the data (which I think will not be necessary in most cases).

So, your function should be defined like this:

  void SetColor(led_color_t * p_color);

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...