Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Passing different variable types to a function

Reply
Thread Tools

Passing different variable types to a function

 
 
Shawn
Guest
Posts: n/a
 
      01-16-2006
As if it won't be clear enough from my code, I'm pretty new to C
programming. This code is being compiled with an ANSI-C compatible
compiler for a microcontroller. That part, I believe, will be
irrelavent. My syntax is surely where I am going wrong.

I'd like to be able to call this routine to read different values from
another device. This routine would be called quite simply as follows:

void main()
{
long test;
read7753(test,3);
}

"test" may be a char, int, unsigned int, long, or unsigned long. My
problem is in figuring out how best to pass the variable that will
receive the value once it is read. That is, how can I get "data" from
my function below back into whatever variable I called it from, e.g.
"test" no matter what type of variable "test" is?

Thanks all, very much for any assistance.




void read7753(unsigned long data, int nbrBytes)
{
unsigned char i;

// Shift bits from the ADE7753.
BitWrPortI(PBDR, &PBDRShadow, 0, 7); //CS Low

for (i = 0; i < nbrBytes*8; ++i) {
BitWrPortI (PFDR, &PFDRShadow, 0, 1);
BitWrPortI (PFDR, &PFDRShadow, 1, 1);

data = data << 1;
data |= BitRdPortI (PCDR, 2);
} // END for

BitWrPortI(PBDR, &PBDRShadow, 1, 7); //CS High

}
 
Reply With Quote
 
 
 
 
Chris Torek
Guest
Posts: n/a
 
      01-16-2006
In article <(E-Mail Removed)>,
Shawn <(E-Mail Removed)> wrote:
>As if it won't be clear enough from my code, I'm pretty new to C
>programming. This code is being compiled with an ANSI-C compatible
>compiler for a microcontroller. That part, I believe, will be
>irrelevent.


Maybe, maybe not. A lot of compilers for particularly-tiny
microcontrollers fail to actually implement ANSI/ISO C, even
in its "freestanding" form.

This newsgroup (comp.lang.c) is mostly dedicated to hosted
compilers, since a lot of things are unpredictable in freestanding
systems, including the type of main(), and whether there is
even a main() at all. That said, however...:

>I'd like to be able to call this routine to read different values from
>another device. This routine would be called quite simply as follows:
>
>void main()
>{


If this were a hosted system, main() would have to have return-type
"int". I suspect this *is* a freestanding system, though, in which
case perhaps this function ought to be named "start" or some such.
Not that it matters too much, because:

> long test;
> read7753(test,3);


this is unlikely to do anything useful. Here "test" is an
uninitialized "auto"-storage-class variable (i.e., not "static"
so not initialized to zero for you). It contains garbage. You
then pass its value to read7753(), because C always passes all
arguments by value.

>}
>
>"test" may be a char, int, unsigned int, long, or unsigned long. My
>problem is in figuring out how best to pass the variable that will
>receive the value once it is read. That is, how can I get "data" from
>my function below back into whatever variable I called it from, e.g.
>"test" no matter what type of variable "test" is?


C always passes all arguments by value. In order to change an object
(loosely, "a variable"), you must pass, as a value, a pointer that
points to some part(s) of that object. The simplest thing, in most
but not all cases, is to pass a pointer to the entire object.

In other words, you do not pass "the object" at all: instead, you
pass "the address of the object". In C, you might write this as:

read7753(&test, 3);

(This makes the rather brash assumption that "test" is made up of
three bytes, in this particular case, but since you are programming
for an embedded microcontroller, you might actually know that it
is indeed a 3-byte, or 24-bit, object, because your platform uses
3 8-bit bytes for a "long". Note, however, that using only 3 8-bit
bytes for a "long" fails to conform to the ANSI/ISO requirements,
even for freestanding compilers, where a "long" must be able to
hold values in the range [-2147483647..+2147483647]. Yes, both of
those numbers are the same -- ones' complement and sign-and-
magnitude representations are permitted. To obtain that range, at
least 32 bits are required, and the only way to make that work with
as few as three bytes is to have at least 11 bits per byte. 11
bits per byte is allowed -- any number from 8 on up is OK -- but
some of your code assumes 8 bits per byte, which is certainly the
most common case today.)

The problem with simply using "&test" here is that &test has type
"pointer to long", or "long *". This would be fine if you were
only ever going to read into "long"s, but if you are going to read
into variables of other types, the read7753() function cannot be
restricted to writing only "long"s.

The solutions (there are many but only two are "reasonable", and
only one is "obviously best" -- for some definitions of obvious
and best -- provided your compiler is in fact ANSI/ISO conformant)
are to use the fact that it is not necessary to point to the
*entire* object. It suffices to point to the "first byte" of the
object. In C, all objects must be "break-up-able" into individual
bytes, which C calls "char"s. You can use a pointer to char --
preferably a pointer to "unsigned char", which avoids the possibility
of trap representations (which your implementation no doubt does
not have anyway, but bear with me) -- to point to the various
bytes, as in:

unsigned char *p;
long somevar;
p = (unsigned char *)&somevar;

After this, you can refer to p[0], p[1], p[2], and so on, to access
the individual bytes making up "somevar". The maximum legal
subscript is (sizeof(long)-1), typically 3 or 7 on most machines
today (the value will depend on the compiler and machine).

Suppose, then, that sizeof(long)==4 and read7753() will fill in
the given number of C bytes (as "unsigned char"s). Then we can
do this:

long test = 0;

read7753((unsigned char *)&test, 3);

The reason for initializing "test" to zero is that read7753() will
only *write* three bytes, but -- per our assumptions above -- the
"long" is made up of four bytes. We initialize all of them, and
then allow read7753() to overwrite three of the four. The remaining
one remains zero, which is likely to be helpful when we go to do
something with the value now in "test". (Or it might not be
useful, but in that case, why bother with all this, when we could
write instead:

unsigned char buf[3];

read7753(&buf[0], 3);

and fill in just the three bytes in "buf", with no wasted fourth
byte? Presumably the point of assembling all the bits together
into a "long" was to do some sort of arithmetic on them.)

This method is likely to work on all compilers that claim to
implement the C language, even if what they actually implement
is something almost but not entirely unlike C. If the compiler
really, actually does implement C, however, there is a "better"
way.

Note that, except when passing the address of some "unsigned char"
object (including the address of the first element of an array of
unsigned char), the call to read7753() above requires a cast. In
C, the presence of a cast does two things:

- instructs the compiler to convert a value of some type to
a new value of some other type (the new type being the one
in parentheses, and a parenthesized type-name constituting
a cast); and

- tells the compiler that, no matter how dubious that
conversion may be, to please shut the he{ck | ll} up about it
and just do it, even if it is clearly, obviously, 100% wrong,
because the programmer knows better.

The first one is all well and good, but the second one introduces
all kinds of opportunities for error. For this reason, it is a
good idea to try to avoid using casts whenever possible -- and
ANSI/ISO C allows avoiding the cast by using "void *".

When you write the prototype for the read7753() function -- including
the one that you will write while defining the function -- you can
give the first argument the type "void *". Note that the memcpy()
and memset() functions make use of "void *", for the same reason.
Thus:

#include <stdlib.h> /* for size_t */

void read7753(void *, size_t);

int main(void) {
long test = 0;

read7753(&test, 3); /* XXX assumes sizeof test >= 3 */
... do something with "test" ...
}

void read7753(void *data0, size_t nbytes) {
unsigned char *data = data0;
... do stuff to fill in data[i] ...
}

While "void *" has been standard since 1990 (the 1989 C standard
was approved in late December 1989, late enough to really be a 1990
thing), a lot of freestanding microprocessor "C compilers" never
got around to implementing a lot of the 1989 standard, much less
the new 1999 standard. So there are some on which "void *" may
not work right.

I will leave the code for working (one bit at a time) with the
"ADE7753" (whatever that is) to someone else, but suffice it to
say that if you are going to read some (variable) number of bytes
from it, you may want to do that one byte ("unsigned char" in C)
at a time.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Argument type of function and safe types and types, arguments canhandle safely ittium C++ 4 12-09-2011 11:05 AM
Passing of pointers of different types to a function using singleparameter at same time. manu C Programming 5 09-17-2009 07:40 AM
Different behaviour in different struct declaration types __PaTeR C Programming 7 01-01-2009 12:13 AM
passing pointer to function - modify in different function not working Kiran C Programming 6 01-18-2007 07:04 PM
Passing pointer to member function to different member function that then calls for_each pookiebearbottom@yahoo.com C++ 8 05-24-2005 01:50 PM



Advertisments