473,320 Members | 1,612 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Passing different variable types to a function

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

}
Jan 16 '06 #1
1 3242
In article <mo********************************@4ax.com>,
Shawn <kl******@hotmail.com> 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 (40°39.22'N, 111°50.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.
Jan 16 '06 #2

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: domeceo | last post by:
can anyone tell me why I cannot pass values in a setTimeout function whenever I use this function it says "menu is undefined" after th alert. function imgOff(menu, num) { if (document.images) {...
20
by: Glenn Venzke | last post by:
I'm writing a class with a method that will accept 1 of 3 items listed in an enum. Is it possible to pass the item name without the enum name in your calling statement? EXAMPLE: public enum...
58
by: jr | last post by:
Sorry for this very dumb question, but I've clearly got a long way to go! Can someone please help me pass an array into a function. Here's a starting point. void TheMainFunc() { // Body of...
11
by: truckaxle | last post by:
I am trying to pass a slice from a larger 2-dimensional array to a function that will work on a smaller region of the array space. The code below is a distillation of what I am trying to...
3
by: Paul Michaud | last post by:
Consider the following: Class A { .... } Class B:A { ....
11
by: John Pass | last post by:
Hi, In the attached example, I do understand that the references are not changed if an array is passed by Val. What I do not understand is the result of line 99 (If one can find this by line...
6
by: MSDNAndi | last post by:
Hi, I get the following warning: "Possibly incorrect assignment to local 'oLockObject' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the...
12
by: Andrew Bullock | last post by:
Hi, I have two classes, A and B, B takes an A as an argument in its constructor: A a1 = new A(); B b = new B(a1);
7
by: TS | last post by:
I was under the assumption that if you pass an object as a param to a method and inside that method this object is changed, the object will stay changed when returned from the method because the...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.