I am working on a C program that uses a Union. The union definition is in FILE_A header file and looks like this...
// FILE_A.h****************************************************
xdata union
{
long position;
char bytes[4];
}CurrentPosition;
If I set the value of CurrentPosition.position in FILE_A.c and then call a function in FILE_B.c that uses the union, the data in the union is back to Zero. This is demonstrated below.
// FILE_A.c****************************************************
int main.c(void)
{
CurrentPosition.position = 12345;
SomeFunctionInFileB();
}
// FILE_B.c****************************************************
void SomeFunctionInFileB(void)
{
// After the following lines execute I see all zeros in the flash memory.
WriteByteToFlash(CurrentPosition.bytes[0];
WriteByteToFlash(CurrentPosition.bytes[1];
WriteByteToFlash(CurrentPosition.bytes[2];
WriteByteToFlash(CurrentPosition.bytes[3];
}
Now, If I pass a long to SomeFunctionInFileB(long temp) and then store it into CurrentPosition.bytes within that function, and finally call WriteBytesToFlash(CurrentPosition.bytes[n]... it works just fine.
It appears as though the CurrentPosition Union is not global. So I tried changing the union definition in the header file to include the extern keyword like this...
extern xdata union
{
long position;
char bytes[4];
}CurrentPosition;
and then putting this in the source (.c) file...
xdata union
{
long position;
char bytes[4];
}CurrentPosition;
but this causes a compile error that says:
C:\SiLabs\Optec Programs\AgosRot\MotionControl.c:76: error 91: extern definition for 'CurrentPosition' mismatches with declaration.
C:\SiLabs\Optec Programs\AgosRot\/MotionControl.h:48: error 177: previously defined here
So what am I doing wrong? How do I make the union global?
Is FILE_A.h really MotionControl.h? If so I think the fix is to define a union type in the header:
typedef
union xdata
{
long position;
char bytes[4];
} xdata;
And declare a global variable of that type elsewhere in a header file (maybe the same one):
extern xdata CurrentPosition; // in a header file
Finally define the global variable in a C file exactly once. Maybe in file_a.c:
xdata CurrentPosition;
Of course a better fix might be to pass the xdata variable you want to write out to flash to SomeFunctionInFileB() so you don't have to depend on a global variable, which are well known to be problematic when not very, very carefully used. And there seems to be no good reason to not pass the data as a parameter:
// in a header file
void SomeFunctionInFileB( xdata const* pPosition);
void SomeFunctionInFileB( xdata const* pPosition)
{
// After the following lines execute I see all zeros in the flash memory.
WriteByteToFlash(pPosition->bytes[0];
WriteByteToFlash(pPosition->bytes[1];
WriteByteToFlash(pPosition->bytes[2];
WriteByteToFlash(pPosition->bytes[3];
}
And call it like so:
int main.c(void)
{
CurrentPosition.position = 12345;
SomeFunctionInFileB( &CurrentPosition);
}
Ideally you need a typedef for the union and an extern declaration in FILE_A.h and the actual definition of the union in FILE_A.c.
-
// FILE_A.h
typedef union
{
long position;
char bytes[4];
} Position;
extern Position CurrentPosition; // declaration
-
// FILE_A.c
#include "FILE_A.h"
Position CurrentPosition; // definition
int main(void)
{
CurrentPosition.position = 12345;
SomeFunctionInFileB();
return 0;
}
-
// FILE_B.c
#include "FILE_A.h"
void SomeFunctionInFileB(void)
{
// now there will be valid data in the flash memory.
WriteByteToFlash(cp.bytes[0];
WriteByteToFlash(cp.bytes[1];
WriteByteToFlash(cp.bytes[2];
WriteByteToFlash(cp.bytes[3];
}
-
You haven't instantiated the union.
You need :
// FILE_A.c****************************************************
#include "File_a.h"
CurrentPosition cp;
int main(void)
{
cp.position = 12345;
SomeFunctionInFileB();
}
// FILE_B.c****************************************************
#include "File_a.h"
extern CurrentPosition cp;
void SomeFunctionInFileB(void)
{
// now there will be valid data in the flash memory.
WriteByteToFlash(cp.bytes[0];
WriteByteToFlash(cp.bytes[1];
WriteByteToFlash(cp.bytes[2];
WriteByteToFlash(cp.bytes[3];
}
If sizeof(long) is not 4, then endianess comes into play...
consider
union{
long position
char bytes[sizeof long];
}
Related
Update: The issue is resolved. Here is code that compiles properly.
---instruction.h---
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
typedef enum OPCODE {ADD = 0x20,ADDI = 0x8,SUB = 0x22,MULT = 0x18,BEQ = 0x4,LW = 0x23,SW = 0x2B} opcode;
/*opcode is OPCODEs alias*/
typedef struct INSTRUCTION {
opcode op;
int rs;
int rt;
int rd;
int Imm;
} inst;
/*inst is INSTRUCTIONs alias*/
#endif // INSTRUCTION_H
---parser.c---
#include <stdio.h>
#include "instruction.h"
void parser(char *instruction)
{
/*Parse character string into instruction components*/
inst set1 = {LW,0,1,2,0};
printf("parsing");
};
int main()
{
char *instruction;
instruction = NULL;
parser(instruction);
};
/*pass in pointer for instruction being passed in*/
/*pointing to address of instruction being passed in*/
/*Parser return type is struct inst*/
I cannot seem to get my enumeration type "opcode" to be recognized in my main c file. I included the header file. I am fairly new to C, so haven't made much ground on the issue for some time now and wanted to see if anyone knew why I was getting the error messages below. My guess is the linking the header file is not working properly. Any help is much appreciated.
---instruction.h----
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
typedef enum {add = 32,addi = 8,sub = 34,mult = 24,beq = 4,lw = 35,sw = 43}opcode;
extern opcode oper;
typedef struct {
opcode op;
int rs;
int rt;
int rd;
int Imm;
}inst;
#endif // INSTRUCTION_H
---Parser.c---
#include <stdio.h>
#include "instruction.h"
void parser(char *inst)
{
/*Parse character string into instruction components*/
struct inst{lw,0,1,2,0};
};
int main()
{
char *instruction;
instruction = NULL;
parser(instruction);
};
struct inst{lw,0,1,2,0};
This looks like it's supposed to be a variable declaration, but I don't see a name for the variable. Try:
struct inst name_of_the_variable = {lw,0,1,2,0};
As a side note, enum values are global constants, so it's probably not a good idea to give them names like lw that can be confused for variables. Standard practice would be to use all-caps for the names and give them a prefix… say, OPCODE_ADD, OPCODE_LW, etc.
This is not a valid variable definition:
struct inst{lw,0,1,2,0};
There's no struct inst defined, only inst, there's no variable name, and you need = to use an initializer. To create a variable of this type an initialize it, you need:
inst myinst = {lw,0,1,2,0};
Also, your function has a parameter named inst which masks the type inst. You need to give it a different name:
void parser(char *instruction)
I'm implementing a little program in C which uses a shared library called "libhelper.so".
The "libhelper.so" defines a struct in it's h-file, but sadly depending on the target-system those definitions are different (libhelper.so is always provided by the system and not by myself):
System A:
struct theStruct {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int bar; // only in System A
};
System B:
struct theStruct {
int fd;
unsigned int flags;
int foo; // in both systems
int foobar; // only in system B
};
In my program, I thought I just define that struct by myself like this:
struct theStruct {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int foobar; // only in system B
int bar; // only in System A
};
As the result of a call to a function in "libhelper.so" I got an instance of "theStruct" and now I though I can just check if "theStructInstance->bar" or "theStructInstance->foobar" is filled with a valid value to detect which implementation has been used by the library.
But it seems that I get just values like 1...6 which looks like the position of the field in the struct.
Has anyone an idea how I can do this?
No, this won't work.
First of all, all the definitions of the structure must be the same, otherwise you get the infamous Undefined Behaviour.
Second, look at the memory layout. What should be the offset to bar from the beginning of the structure? The first and the third definitions don't agree on this (the fields are most likely to be located consecutively).
Maybe you can try a union?
struct theStruct {
int fd;
unsigned int flags;
struct config config;
int foo; // in both systems
union {
int bar; // only in System A
int foobar; // only in system B
};
};
If you choose this, you should use only bar on System A and only foobar on System B.
If the two systems are incompatible, and the actual type needed for bar is not available on System B (and vice versa), you can do with the following code:
struct theStruct {
int fd;
unsigned int flags;
struct config config;
int foo; // in both systems
#ifdef SYSTEM_A
int bar; // only in System A
#else
#ifdef SYSTEM_B
int foobar; // only in system B
#else
#pragma error(either SYSTEM_A or SYSTEM_B must be enabled)
#endif
#endif
};
This way you will be always working with either with code compiled for System A or for System B, so you'll need to have different executables (which seems to be unavoidable anyway if you are compiling for the systems so much different).
You'll need to wrap parts of your code accessing the fields into #ifdefs:
#ifdef SYSTEM_A
s.bar = 5;
#endif
-- otherwise you'll get compile errors on System B.
Another possible solution would be to write platform dependent code to handle each of the individual structs, and then load their data into a common struct. This would then allow you to deal with the same members of the struct, no matter the code path, rather than always referencing one of the two union members based on the system:
struct mystruct;
mystruct.member1 = theStruct.member1; //the common part of the struct
mystruct.member2 = theStruct.member2;
#ifdef platform1
mystruct.member3 = theStruct.p1member; //specific to platform1
mystruct.member4 = -1;
#else
mystruct.member3 = -1;
mystruct.member4 = theStruct.p2member; //specific to platform2
#endif
Here is an approach to think about.
A bit of background about the assumptions I am making first.
It sounds like you have some function libraryFunction () that returns a pointer to a struct theStruct. However the actual layout of the struct theStruct depends on the particular system on which your application is running. In this struct is some information that you need to access. You do not specify the calling arguments or signature of the library function and if the pointer to the struct theStruct is returned as a function value or a pointer to a pointer is part of the argument list. I will assume it is a function return value.
Create a struct you define for the information that you want. Create two files each of which has a function that takes a void pointer and a pointer to your new struct and then fills in your struct with the data you want from the library supplied struct. Each of these two files will be compiled with a particular system target specified (SystemA or SystemB) so that your conversion function will interpret the struct provided by the library function depending on the target system and fill in your struct with the data you want.
file 1 for System A
// copy of the struct used in System A which is in the library header file
// put here for reference only as should be in the header file
struct theStruct {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int bar; // only in System A
};
// my struct that contains the data from struct theStruct that I want
// would be in a header file included into each of these files but here for reference
struct myConvertStruct {
int foo;
};
void convert2SystemA (void *structPtr, struct *myStruct)
{
myStruct->foo = ((struct theStruct *)structPtr)->foo;
}
file 2 for System B
// copy of the struct used in System B which is in the library header file
// put here for reference only as should be in the header file
struct theStruct {
int fd;
unsigned int flags;
int foo; // in both systems
int foobar; // only in system B
};
// my struct that contains the data from struct theStruct that I want
// would be in a header file included into each of these files but here for reference
struct myConvertStruct {
int foo;
};
void convert2SystemB (void *structPtr, struct *myStruct)
{
myStruct->foo = ((struct theStruct *)structPtr)->foo;
}
file 3 using the conversion functions
// my struct that contains the data from struct theStruct that I want
// would be in a header file included into each of these files but here for reference
struct myConvertStruct {
int foo;
};
{
struct myConvertStruct myStruct;
// some function body and now we come to the library call
if (mySystem == SystemA) {
void *pStruct = libraryFunction (......);
convert2SystemA (pStruct, &myStruct);
} else if (mySystem == SystemB) {
void *pStruct = libraryFunction (......);
convert2SystemB (pStruct, &myStruct);
} else {
// some error conditions
}
// now use the data that you have pulled as you want to use it
}
The reason why your proposal won't work is that the offset to the foo member is different for System A and System B. You say that you can only figure out what System you are using at runtime. So, when System B sets foo, it will likely end up setting something inside of config instead.
enum system { SystemUnknown, SystemA, SystemB };
struct theStructSystemA {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int bar; // only in System A
};
struct theStructSystemB {
int fd;
unsigned int flags;
int foo;
int foobar;
};
struct myStruct {
union {
struct theStructSystemA a;
struct theStructSystemB b;
} u;
enum system sys;
};
struct myStruct s = { 0 };
Now, you can set bar to some invalid value: s.u.a.bar = -1, for example. Now, when you call into your library, you can check:
s.u.a.bar = -1;
some_libhelper_call((void *)&s);
if (s.u.a.bar != -1) s.sys = SystemA;
else s.sys = SystemB;
So now, after s.sys is known, you can switch to a different code path that deals entirely with a known system version.
I have the following header file:
typedef struct my_data my_data_t;
my_data_t* new_my_data(void);
void free_my_data(my_data_t* my_data);
And the corresponding c file:
typedef struct my_data
{
int val;
} my_data_t;
my_data_t* new_my_data()
{
my_data_t* ptr = (my_data_t*)malloc(sizeof(my_data_t));
return ptr;
}
void free_my_data(my_data_t* my_data)
{
free(my_data);
}
I would like to create in instance of my_data_t in static memory without using malloc. I'd like to do this by adding the following to the header file:
int sizeof_my_data(void);
...and this to the c file:
int sizeof_my_data()
{
return sizeof(my_data_t);
}
...and doing something like this:
static my_data_t* my_data_instance = static_alloc(sizeof_my_data());
Is this possible? I'd like to do this because the target machine for this code is a microprocessor that doesn't handle malloc (in our case, it's best that all structures be held in static memory), and I'd like to keep the actual data structure of my_data hidden from the code that implements it. Any other suggestions on how to accomplish the goal are welcome. Thanks.
The usual way of doing this is to create an opaque struct in your header file with the correct size. For example:
#define MY_DATA_SIZE 32
struct my_data_t
{
char opaque_data[MY_DATA_SIZE];
};
This is how the various pthreads data types (such as pthread_mutex_t) are defined.
How about adding to your header file
my_data_t *get_static_data();
and to your c file
my_data_t *get_static_data()
{
static my_data_t static_my_data;
return &static_my_data;
}
Rookie question FYI.
Whenever I compile/run the code, extern tolayer2(rtpktTo1); I receive a warning.
The warning reads, as in the title, Warning: parameter names (without types) in function declaration
Any help appreciated.
node0.c
extern struct rtpkt {
int sourceid; /* id of sending router sending this pkt */
int destid; /* id of router to which pkt being sent
(must be an immediate neighbor) */
int mincost[4]; /* current understanding of min cost to node 0 ... 3 */
};
/* Create routing packets (rtpkt) and send to neighbors via tolayer2(). */
struct rtpkt rtpktTo1;
rtpktTo1.sourceid = 0;
rtpktTo1.destid = 1;
rtpktTo1.mincost[0] = minCost[0];
rtpktTo1.mincost[1] = minCost[1];
rtpktTo1.mincost[2] = minCost[2];
rtpktTo1.mincost[3] = minCost[3];
extern tolayer2(rtpktTo1);
prog3.c
tolayer2(packet)
struct rtpkt packet;
{
/* This has a lot of code in it */
}
The assignments to rkpktTo1.* are not apparently in a function or declaration, unless this is a code fragment. Wrap them in a function. The warning is a bit misleading.
The declaration of tolayer2() should have a return type as well as a parameter type. Since there isn't one, int is assumed. This may not be what is intended, but it should compile without warnings and errors:
node0.c
struct rtpkt {
int sourceid; /* id of sending router sending this pkt */
int destid; /* id of router to which pkt being sent
(must be an immediate neighbor) */
int mincost[4]; /* current understanding of min cost to node 0 ... 3 */
};
/* Create routing packets (rtpkt) and send to neighbors via tolayer2(). */
void function () {
struct rtpkt rtpktTo1;
rtpktTo1.sourceid = 0;
rtpktTo1.destid = 1;
rtpktTo1.mincost[0] = minCost[0];
rtpktTo1.mincost[1] = minCost[1];
rtpktTo1.mincost[2] = minCost[2];
rtpktTo1.mincost[3] = minCost[3];
}
extern void tolayer2(struct rtpkt *rtpktTo1);
prog3.c
void
tolayer2(struct rtpkt *packet)
{
/* This has a lot of code in it */
}
Passing a structure by value is often not appropriate, so I have changed it to pass by reference.
In prog3.c
tolayer2(packet)
struct rtpkt packet;
{ /* ... */ }
This is old syntax (very old: before ANSI standardized C in 1989), but perfectly legal in C89 and C99. Don't use it though: prefer
int tolayer2(struct rtpkt packet)
{ /* ... */ }
In the declaration extern tolayer2(rtpktTo1);, rtpktTo1 is a parameter name (like the error says), while you should give a type there:
extern tolayer2(struct rtpkt);
or
extern tolayer2(struct rtpkt *);
or
extern tolayer2(struct rtpkt const *);
or similar, since that is what the compiler needs to know about your function before compiling client code. The parameter name is useless to the compiler at this point and therefore optional.
(And really, you should add a return type as well, and note that extern has no meaning in your struct definition.)
As the title says, keep getting this error when trying to compile. From Googling this error people have said that it is not declared in the header file but my function is static and it is not in a header file, I prototyped it.`
#include <recGbl.h>
#include <devSup.h>
#include <devLib.h>
#include <drvIpac.h>
#include <dbScan.h>
#include <epicsExport.h>
static int cardinit(cardinfo *card); // <-- line that gives the error
typedef struct cardinfo{
struct cardinfo *next;
struct io_mem_read *pMem; /* IP register (A16) mem address */
word *rambase; /* RAM conversion memory mem address*/
int isconfigured;
int doram; /* 1 if we are using the RAM to output data.
0 if we are writing to registers (AO style) */
int cardnum;
int vmeslotnum;
int ipslotnum;
/* these values mirror the hardware registers */
word csr;
word offset;
word numconv;
word clockrate;
word vectnum;
word dacval[MAXSIGNAL];
word oldispresent;
/* used to detect a reinsertion of a carrier card.
see subroutine ispresent() below. */
/* use to update process variables */
IOSCANPVT ioscanpvt;
} cardinfo;
static int Hy8402init(int vmeslot, int ipslot, int clockrate) {
cardinfo *card;
card->vmeslotnum = vmeslot;
card->ipslotnum = ipslot;
card->cardnum = 1;
card->clockrate = clockrate;
card->vectnum = 10;
cardinit(card);
return TRUE;
}
static int cardinit(cardinfo *card){
word rprobe;
int res;
volatile word *ramptr;
card->pMem= ipmBaseAddr(card->vmeslotnum,
card->ipslotnum,ipac_addrIO);
if (card->pMem==NULL){
printf("Error in %s",devstr);
printf( "%s: Cannot determine base address\n",devstr);
return FALSE;
}
res=devReadProbe(sizeof (word),(char *) card->pMem,(char *) &rprobe);
if (res!=OK){
printf("%s: NO DEVICE at %x (vmeslot %d, ipslot %d)\n",devstr,
(int)card->pMem,
card->vmeslotnum,card->ipslotnum);
return FALSE;
}
return TRUE;
}
`
cardinfo struct is still undefined on the line with error. Put a forward declaration before it:
struct cardinfo;
static int cardinit(struct cardinfo *card);
This line of code:
static int cardinit(cardinfo *card);
should be added after the definition of your cardinfo structure.
You need to put the line
static int cardinit(cardinfo *card);
after the definition of the cardinfo structure.
At that line, the compiler doesn't yet know that cardinfo is a struct. Precede it with the line struct cardinfo;
You have declared a function which has a input variable of a type which the compiler is not aware when it parses it. i.e the struct defintion follows your function declaration.
So please do a forward declaration of the structure when you want to compile such code.
In computer programming, a forward declaration is a declaration
of an identifier (denoting an entity such as a type, a variable, or a
function) for which the programmer has not yet given a complete definition.
This link has a nice article on when full declarations are not required.