since now I've been reading Stackoverflow for a long time and I've learned a lot.
But now I have a problem, I couldn't find on Stackoverflow, even it should be kind of a "standard" question. So please forgive me if this topic has been answered already.
Problem:
I'am writing a module with defined interfaces for input and output structures.
It should be some kind of a "multiplexer" with maybe three inputs and one output.
The module should switch one of the inputs to the output (depending on some logic).
A working example is shown here:
#include <stdio.h>
typedef struct{
short myVariable1;
short myVariable2;
} myType;
struct input_type{
myType Inp1;
myType Inp2;
myType Inp3;
};
struct output_type{
myType Out1;
};
struct input_type input;
struct output_type output;
void main(){
for (int i=0; i<10; i++){ // this for loop simulates a cyclic call of a function where all the inputs are written
input.Inp1.myVariable1 = i;
input.Inp2.myVariable1 = i*2;
input.Inp3.myVariable1 = i*3;
printf("Inp1: %d | Inp2: %d | Inp3: %d \n",input.Inp1.myVariable1,input.Inp2.myVariable1,input.Inp3.myVariable1);
output.Out1 = input.Inp2; // Actual routing is done here, but i want to avoid this copy by working on the same dataset (e.g. input.InpX)
printf("Out: %d\n",output.Out1.myVariable1);
}
}
In this snipped, the structures are simply copied every cycle.
To avoid this step, I could do the following:
#include <stdio.h>
typedef struct{
short myVariable1;
short myVariable2;
} myType;
struct input_type{
myType Inp1;
myType Inp2;
myType Inp3;
};
struct output_type{
myType * Out1;
};
struct input_type input;
struct output_type output;
void main(){
output.Out1 = &input.Inp2; // Actual routing is done here; But in this case, the output structure includes a pointer, therefore all other modules need to dereference Out1 with "->" or "*"
for (int i=0; i<10; i++){ // this for loop simulates a cyclic call of a function where all the inputs are written
input.Inp1.myVariable1 = i;
input.Inp2.myVariable1 = i*2;
input.Inp3.myVariable1 = i*3;
printf("Inp1: %d | Inp2: %d | Inp3: %d \n",input.Inp1.myVariable1,input.Inp2.myVariable1,input.Inp3.myVariable1);
printf("Out: %d\n",output.Out1->myVariable1);
}
}
But in this case, the output structure is not compatible to the existing interface anymore.
Access to Out1 would need dereferencing.
Is it possible to avoid copying the structures from one to another without changing my interface?
Thanks in advance for your answers!
Rees.
Is it possible to avoid copying the structures from one to another without changing my interface?
By "the existing interface", I take you to mean that you have code that consumes objects of this type ...
struct output_type{
myType Out1;
};
... and you would like to avoid modifying that code.
In that case, no, you cannot substitute
struct output_type{
myType * Out1;
};
. Moreover, it is inherent in the design of the former structure that populating the myType that is a direct member involves copying all the data you care about, whether on a per-member basis or on a whole-structure basis.
At this point, I would recommend that you just stick with making those copies, until and unless you discover that doing so causes performance or memory usage to be unsatisfactory. Changing at this point would involve more than just syntactic changes: it would require careful review of all uses of struct output_type to find and mitigate any situations where the code relies on the properties of the original structure (such as to be confident of non-aliasing).
Related
I have the following c code:
struct {
short s;
int n;
} variableName;
I want to write a function to capture this variable like so
void func(MyStruct* var){
//do stuff
}
func(&variableName);
I would like to do this without providing a definition for the struct. Is there a way to capture variableName?
No, you can't pass an "anonymous" struct into a function in C. You could of course define your function to accept the arguments individually:
void func(short s, int n) { ... }
Or you can define the MyStruct structure in a place that both the function and the calling code has visibility to. Note that the whole struct is passed by value (copy) when you do that, which may be the behavior you want here (or may not be).
You may be looking for something more like a "dictionary" or "associative array" or "hash" type that many other languages provide, with arbitrary key value pairs in it. Pure C does not have a facility for this; the compiler wants to know the layout of a structure in advance.
(I'm not sure if you might be asking about a slightly more esoteric idea, which is hiding the composition of a structure and passing around an "opaque handle" out of and into an API. There are ways to structure that in C, but please say so if that's what you're talking about.)
Completely overlooked "I would like to do this without providing a definition for the struct. Is there a way to capture variableName?" in the OP, unless it was edited after. The question makes less sense now, but heres how you could normally pass a struct to a function for future readers.
#include <stdio.h>
struct StructName{
short s;
int n;
};
void func(struct StructName struct_var){
printf("Param values are: %4X %4X\n", struct_var.s & 0xFFFF, struct_var.n & 0xFFFF);
}
int main(){
struct StructName struct_var;
struct_var.s = 0xDEAD;
struct_var.n = 0xBEEF;
func(struct_var);
}
//It looks like you are trying to use the definition as a variable. Here the definition is StructName and the variable is struct_var.
this sample code outputs:
Param values are: DEAD BEEF
If you use clang or gcc, you may be able to use typeof:
struct foo {
struct {
int i;
} anon;
} foo;
void do_something(typeof(foo.anon)* member) {
member->i = 1;
}
If there is no global instance of your type, you may be able to use typeof((struct foo){}.anon).
This comes with a lot of downsides. The most obvious ones are that:
it's not standard, and it ties you to clang/gcc
it's pretty darn ugly
it might not behave as you expect anyway
For instance, structurally-equivalent anonymous types do not have the same type, so in something like this:
struct foo {
struct {
int i;
} anon1;
struct {
int i;
} anon2;
} foo;
anon1 and anon2 both have a different type, meaning that typeof one of them cannot be used to refer to both.
In the long run, you will almost certainly find that it's worth naming the structures, especially if you use them as function arguments. For instance, if you want to make your variable available from a header, I think that you'll have to work pretty hard to keep it anonymous.
Although it's not particularly pretty and not compatible with C++, C puts the name of nested declarations in the global namespace, so this is portable and it's not a very big code change to front-load:
struct {
struct not_anon {
int i;
} anon;
} foo;
void do_something(struct not_anon* member) {
member->i = 1;
}
please....
I am trying to make library which is intended like a lib based on struct
I wanna reach something like "mats.basic.add(1,1);"
first error when build is first line inside struct (both of them) and then
are, although editors hints me after dot operation like add or sub
next errors are "uknown members add, sub
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t (*p_fn1)(uint8_t,uint8_t);
uint8_t fn_add(uint8_t num1,uint8_t num2){
return num1+num2;
}
uint8_t fn_sub(uint8_t num1,uint8_t num2){
return num1-num2;
}
typedef struct mats {
p_fn1 add=fn_add;
p_fn1 sub=fn_sub;
}mats;
void init_mats(mats* t_mats){
t_mats->add=fn_add;
t_mats->sub=fn_sub;
}
int main()
{
mats mats_s;
init_mats(&mats_s);
uint8_t c=mats_s.add(1,1);
printf("%d",c);
return 0;
}
thanks a lot
You're attempting to initialize struct members when you define the struct. That's invalid syntax.
Remove those initializers from the definition.
typedef struct mats {
p_fn1 add;
p_fn1 sub;
}mats;
If you want to have methods that can be called on your types, write your program in C++. It has that feature; C does not.
There isn't any way to do this in pure C that won't be clumsy to write, slow to run, and/or use inappropriate amounts of memory. The specific way that you're trying doesn't work at all because you're trying to set fields on a type, rather than on an instance of that type, but even if you fixed that, you'd still run into some other fundamental limitations of the language.
I want to write data to an array of structures. The structure itself is declared and defined inside main(). I have 3 functions that need to write, process and read the data from the array.
All I could achieve was creating a global struct declaration and then passing pointers to them.
Is it possible without making the structure declaration global?
The relevant code is posted below.
This is my struct declaration outside of main()
struct date
{
int d;
int m;
int y;
};
struct stud
{
int roll;
char name[30];
struct date dob;
int P;
int C;
int M;
float PCM;
char flag_in;
char flag_pro;
};
These are the function defintions.
void getdata(struct stud *S)
{
scanf("%d", &(S->roll));
scanf("%s", (S->name));
//Similarly for dob, p, c, m
(S->flag_in)='1';
return;
}
void process(struct stud *S)
{
if(S->flag_in=='1')
{
S->PCM=(S->P + S->C + S->M)/3;
S->flag_pro='1';
}
}
void display(struct stud *S)
{
for(int x=0; x<10; x++)
if(S[x].flag_in=='1')
{
//printing the data to the console output
}
}
These are the function calls:
getdata(&S[i]);
process(&S[x]);
display(S);
It's entirely valid to not want to expose other parts of your program to the internal structure of a type.
C is extremely well placed to do this with considerable elegance.
Call this X.h
//Declaration of X as pointing to an incomplete struct XS.
//This says there's such a thing as a struct XS but not how it is laid out or even how big it is.
//It also says X is a short-hand for a pointer to a mysterious XS structure.
typedef struct XS* X;
//Creates an X and returns a pointer to it. Remember to call destroyX(.) exactly once - later.
X createX(void);
//Does something with X and returns some number.
int doXThing(X x);
//Destroys an X. Must be called exactly once for each return value from createX().
void destroyX(X x);
This is prog.c (containing your main(.) function).
#include <stdlib.h>
#include <stdio.h>
#include "X.h"
//Now we actually define that mysterious structure.
//Other translation units will not see this.
struct XS {
int v;
} ;
//Here we have size and layout so we can actually implement it.
X createX(void){
X x=malloc(sizeof(struct XS));//Explicit allocation of 'implementation struct'.
if(x==NULL){
return NULL;//malloc(.) failed.
}
x->v=0;
return x;
}
int doXThing(X x){
return (x->v)++;
}
void destroyX(X x){
free(x);
}
int main(void) {
X x=createX();
printf("%d\n",doXThing(x));
printf("%d\n",doXThing(x));
printf("%d\n",doXThing(x));
destroyX(x);
return 0;
}
Notice that the other modules using #include "X.h" don't see the layout of the structures.
The upside is the implementation can change normally without recompilation - just re-linking.
The downside is that without access to the size and layout of X those 'using' modules need to delegate all the work to a module that does!
That means all Xs have to come of the free-store (or a static pool inside the implementing module..).
This model is really rather common and quite powerful as it allows for complete abstraction and data hiding.
If you're willing to do a load of casting you don't even need to 'reveal' the name XS.
typedef XSHandle* X;
Or even
typedef unsigned short* X; //Little used type... Illegal but works on most platforms - check your documentation of use char (bare, signed or unsigned).
But don't get led into:
typedef void* X;
In C. void* is so promiscuous in its casting you will get into trouble!
C++ however behaves far better about that.
PS: It's not normal to put the implementation in the same translation unit as main(.).
It's not wrong in a small project but it's not normal to get into quite so much abstraction in a small project.
PPS: A stated this method provides for a very high degree of OO programming. It may be of interest that Stroustrup made documented design decisions to NOT do this for all classes in C++ because it has a fixed and unavoidable overhead and he gave himself a 'zero-overhead principle' and wanted to provide a way of 'mixing' abstraction with direct access to object layout (allocation as local variable, direct access to members, inline functions,...).
I think he made the right decision as a language level decision for the intended use of C++. That doesn't make it a bad design pattern where appropriate.
What you could do is declare the struct inside the main. and pass the pointer when the functions are called:
//this code is inside main
struct stud arr[10]; // create an array for the struct
display(arr); //pass the pointer to function
since the main is called before the functions the data will not be deleted and will exist on the processing of other functions which can pass the pointer between them.
Although I suggest not to use this method if the functions are not for one purpose (change value, print, etc...). If the data struct is used as global declare it as global.
I have the impression that you are not clear on the difference between the definition of a struct type and an instance of that type.
To be able to work with a struct variable, your functions have to see the full type declaration, such that the compiler knows how the variable is structured and to access the different fields. But there is no need that they see the variable declaration as such. The variable can be accessed without problems through a pointer that you pass as argument.
If you have your structure within the main() then the scope of this structure is local to main()
Since structures are user-defined data-types it can't used as you try because this new type is just visible within the main()
So the functions which you have defined will not have visibility of the structure.
So in order to handle this the structure should be made global.
So a binary answer to your question
Is it possible without making the structure declaration global?
is NO
Is it possible without making the structure declaration global?
No, any functions needs a struct's definition to be visible (globally) for it to be useable. Otherwise, from the function's viewpoint, the invisible struct would be an undefined identifier.
Local structs will not be visible anywhere outside the function.
The more important question would be what do you save in making it local as opposed to global? One thing that comes to my mind is that compilation time might be faster since if declared global in a header where lot of TUs see it unnecessarily.
I'm trying to create structs with default values. I don't know how to accomplish this because every code that I see, is about initialising, and I would it for the natural way like...
struct stuff {
int stuff_a = 1;
int stuff_b = 2...
...and so on...
};
and looking about, I found this (C++) code:
struct a{ a() : i(0), j(0) {}; INT i; INT j;}
I never saw anything like this for C. Please, help me to understand it; I think that it is very nice!
UPDATE: Wait, I'm asking about C!!!! Why changed my question? If that is not possible in C just say... I don't know C++, I didn't know that was about C++...
If you want to set a struct object in one go and you have a C99 compiler, try this:
struct stuff {
int stuff_a;
int stuff_b;
// and so on...
};
struct stuff foo;
/* ... code ... */
foo = (struct stuff){.stuff_b = 42, .stuff_a = -1000};
Otherwise, with a C89 compiler, you have to set each member one by one:
foo.stuff_b = 42;
foo.stuff_a = -1000;
Running example # ideone : http://ideone.com/1QqCB
The original line
struct a{ a() : i(0), j(0) {} INT i; INT j;}
is a syntax error in C.
As you have probably learned from the other answers, in C you can't declare a structure and initialize it's members at the same time. These are different tasks and must be done separately.
There are a few options for initializing member variables of a struct. I'll show a couple of ways below. Right now, let's assume the following struct is defined in the beginning of the file:
struct stuff {
int stuff_a;
int stuff_b;
};
Then on your main() code, imagine that you want to declare a new variable of this type:
struct stuff custom_var;
This is the moment where you must initialize the structure. Seriously, I mean you really really must! Even if you don't want to assign specific values to them, you must at least initialize them to zero. This is mandatory because the OS doesn't guarantee that it will give you a clean memory space to run your application on. Therefore, always initialize your variables to some value (usually 0), including the other default types, such as char, int, float, double, etc...
One way to initialize our struct to zero is through memset():
memset(&custom_var, 0, sizeof(struct stuff));
Another is accessing each member individually:
custom_var.stuff_a = 0;
custom_var.stuff_b = 0;
A third option, which might confuse beginners is when they see the initialization of struct members being done at the moment of the declaration:
struct stuff custom_var = { 1, 2 };
The code above is equivalent to:
struct stuff custom_var;
custom_var.stuff_a = 1;
custom_var.stuff_b = 2;
... create structs with default values ...
That is impossible in C. A type cannot have default values. Objects of any type cannot have a default value other than 0, though they can be initialized to whatever is wanted.
The definition of a struct is a definition of a type, not of an object.
What you asking is about the same thing as a way to have ints default to, say, 42.
/* WRONG CODE -- THIS DOES NOT WORK */
typedef int int42 = 42;
int42 a;
printf("%d\n", a); /* print 42 */
Or, adapting to your example
/* WRONG CODE -- THIS DOES NOT WORK */
struct stuff {
int42 stuff_a;
int65536 stuff_b;
}
struct stuff a;
printf("%d\n", a.stuff_b); /* print 65536 */
Update: This answer assumes we 're talking about C++ because the code posted in the answer is not legal C.
struct a {
a() : i(0), j(0) {} // constructor with initialization list
int i;
int j;
}
The line marked with the comment is simply the constructor for instances of struct a (reminder: structs are just like classes, except that the default member visibility is public instead of private).
The part after the : is called an initialization list: it allows you to initialize the members of the struct with values (either constants or passed as constructor parameters). Initialization of members in this list happens before the body of the constructor is entered. It is preferable to initialize members of classes and structs this way, if at all possible.
See also C++: Constructor versus initializer list in struct/class.
in C (pre C99) the following also works:
#include <stdio.h>
typedef struct
{
int a;
int b;
int c;
} HELLO;
int main()
{
HELLO a = {1,2,3};
printf("here: %d %d %d\n",a.a,a.b,a.c);
exit(1);
}
See codepad
I'm not sure quite sure what your problem is. The standard way of initialising structures in c is like this:
struct a_struct my_struct = {1, 2};
Or the more recent and safer:
struct a_struct my_struct = {.i1 = 1, .i2 = 2};
If there is more than one instance of a structure, or it needs to be re-initialised, it is useful to define a constant structure with default values then assign that.
typedef struct a_struct {
int i1;
int i2;
} sa;
static const sa default_sa = {.i1 = 1, .i2 = 2};
static sa sa1 = default_sa;
static sa sa2 = default_sa;
// obviously you can do it dynamically as well
void use_temp_sa(void)
{
sa temp_sa = default_sa;
temp_sa.i2 = 3;
do_something_with(&temp_sa);
}
// And re-initialise
void reset_sa(sa *my_sa)
{
*my_sa = default_sa;
}
Type initializer is not possible in C.
A value must be stored in the memory.
A type does not occupy memory, what occupies memory is a variable of that type.
struct stuff; is a type; it does not occupy memory
struct stuff aStuff; is a variable of that type; aStuff occupies memory
Because a type does not occupy memory, it is not possible to save values into a type.
If there is syntactic sugar to support store/initialize values into a type then there must be additional code that is inserted to assign values to every instant variables of that type (e.g: in constructor in C++). This will result in a less efficient C if this feature is available.
How often do you need to retain this default values? I think it is unlikely. You can create a function to initialize variable with the default values or just initialize every fields with the values you want. So type initializer is not fundamental thing. C is about simplicity.
Can't initialize values within a structure definition.
I'd suggest:
typedef struct {
int stuff_a;
int stuff_b;
} stuff ;
int stuffInit(int a, int b, stuff *this){
this->stuff_a = a;
this->stuff_b = b;
return 0; /*or an error code, or sometimes '*this', per taste.*/
}
int main(void){
stuff myStuff;
stuffInit(1, 2, &myStuff);
/* dynamic is more commonly seen */
stuff *dynamicStuff;
dynamicStuff = malloc(sizeof(stuff)); /* 'new' stuff */
stuffInit(0, 0, dynamicStuff);
free(dynamicStuff); /* 'delete' stuff */
return 0;
}
Before the days of Object Oriented Programming (C++), we were taught "Abstract Data Types".
The discipline said 'never access your data structures directly, always create a function for it' But this was only enforced by the programmer, instructor, or senior developer, not the language.
Eventually, the structure definition(s) and corresponding functions end up in their own file & header, linked in later, further encapsulating the design.
But those days are gone and replaced with 'Class' and 'Constructor' OOP terminology.
"It's all the same, only the names have changed" - Bon Jovi.
I'm having a very big struct in an existing program. This struct includes a great number of bitfields.
I wish to save a part of it (say, 10 fields out of 150).
An example code I would use to save the subclass is:
typedef struct {int a;int b;char c} bigstruct;
typedef struct {int a;char c;} smallstruct;
void substruct(smallstruct *s,bigstruct *b) {
s->a = b->a;
s->c = b->c;
}
int save_struct(bigstruct *bs) {
smallstruct s;
substruct(&s,bs);
save_struct(s);
}
I also wish that selecting which part of it wouldn't be too much hassle, since I wish to change it every now and then. The naive approach I presented before is very fragile and unmaintainable. When scaling up to 20 different fields, you have to change fields both in the smallstruct, and in the substruct function.
I thought of two better approaches. Unfortunately both requires me to use some external CIL like tool to parse my structs.
The first approach is automatically generating the substruct function. I'll just set the struct of smallstruct, and have a program that would parse it and generate the substruct function according to the fields in smallstruct.
The second approach is building (with C parser) a meta-information about bigstruct, and then write a library that would allow me to access a specific field in the struct. It would be like ad-hoc implementation of Java's class reflection.
For example, assuming no struct-alignment, for struct
struct st {
int a;
char c1:5;
char c2:3;
long d;
}
I'll generate the following meta information:
int field2distance[] = {0,sizeof(int),sizeof(int),sizeof(int)+sizeof(char)}
int field2size[] = {sizeof(int),1,1,sizeof(long)}
int field2bitmask[] = {0,0x1F,0xE0,0};
char *fieldNames[] = {"a","c1","c2","d"};
I'll get the ith field with this function:
long getFieldData(void *strct,int i) {
int distance = field2distance[i];
int size = field2size[i];
int bitmask = field2bitmask[i];
void *ptr = ((char *)strct + distance);
long result;
switch (size) {
case 1: //char
result = *(char*)ptr;
break;
case 2: //short
result = *(short*)ptr;
...
}
if (bitmask == 0) return result;
return (result & bitmask) >> num_of_trailing_zeros(bitmask);
}
Both methods requires extra work, but once the parser is in your makefile - changing the substruct is a breeze.
However I'd rather do that without any external dependencies.
Does anyone have any better idea? Where my ideas any good, is there some availible implementation of my ideas on the internet?
From your description, it looks like you have access to and can modify your original structure. I suggest you refactor your substructure into a complete type (as you did in your example), and then make that structure a field on your big structure, encapsulating all of those fields in the original structure into the smaller structure.
Expanding on your small example:
typedef struct
{
int a;
char c;
} smallstruct;
typedef struct
{
int b;
smallstruct mysub;
} bigstruct;
Accessing the smallstruct info would be done like so:
/* stack-based allocation */
bigstruct mybig;
mybig.mysub.a = 1;
mybig.mysub.c = '1';
mybig.b = 2;
/* heap-based allocation */
bigstruct * mybig = (bigstruct *)malloc(sizeof(bigstruct));
mybig->mysub.a = 1;
mybig->mysub.c = '1';
mybig->b = 2;
But you could also pass around pointers to the small struct:
void dosomething(smallstruct * small)
{
small->a = 3;
small->c = '3';
}
/* stack based */
dosomething(&(mybig.mysub));
/* heap based */
dosomething(&((*mybig).mysub));
Benefits:
No Macros
No external dependencies
No memory-order casting hacks
Cleaner, easier-to-read and use code.
If changing the order of the fields isn't out of the question, you can rearrange the bigstruct fields in such a way that the smallstruct fields are together, and then its simply a matter of casting from one to another (possibly adding an offset).
Something like:
typedef struct {int a;char c;int b;} bigstruct;
typedef struct {int a;char c;} smallstruct;
int save_struct(bigstruct *bs) {
save_struct((smallstruct *)bs);
}
Macros are your friend.
One solution would be to move the big struct out into its own include file and then have a macro party.
Instead of defining the structure normally, come up with a selection of macros, such as BEGIN_STRUCTURE, END_STRUCTURE, NORMAL_FIELD, SUBSET_FIELD
You can then include the file a few times, redefining those structures for each pass. The first one will turn the defines into a normal structure, with both types of field being output as normal. The second would define NORMAL_FIELD has nothing and would create your subset. The third would create the appropriate code to copy the subset fields over.
You'll end up with a single definition of the structure, that lets you control which fields are in the subset and automatically creates suitable code for you.
Just to help you in getting your metadata, you can refer to the offsetof() macro, which also has the benefit of taking care of any padding you may have
I suggest to take this approach:
Curse the guy who wrote the big structure. Get a voodoo doll and have some fun.
Mark each field of the big structure that you need somehow (macro or comment or whatever)
Write a small tool which reads the header file and extracts the marked fields. If you use comments, you can give each field a priority or something to sort them.
Write a new header file for the substructure (using a fixed header and footer).
Write a new C file which contains a function createSubStruct which takes a pointer to the big struct and returns a pointer to the substruct
In the function, loop over the fields collected and emit ss.field = bs.field (i.e. copy the fields one by one).
Add the small tool to your makefile and add the new header and C source file to your build
I suggest to use gawk, or any scripting language you're comfortable with, as the tool; that should take half an hour to build.
[EDIT] If you really want to try reflection (which I suggest against; it'll be a whole lot of work do get that working in C), then the offsetof() macro is your friend. This macro returns the offset of a field in a structure (which is most often not the sum of the sizes of the fields before it). See this article.
[EDIT2] Don't write your own parser. To get your own parser right will take months; I know since I've written lots of parsers in my life. Instead mark the parts of the original header file which need to be copied and then rely on the one parser which you know works: The one of your C compiler. Here are a couple of ideas how to make this work:
struct big_struct {
/**BEGIN_COPY*/
int i;
int j : 3;
int k : 2;
char * str;
/**END_COPY*/
...
struct x y; /**COPY_STRUCT*/
}
Just have your tool copy anything between /**BEGIN_COPY*/ and /**END_COPY*/.
Use special comments like /**COPY_STRUCT*/ to instruct your tool to generate a memcpy() instead of an assignment, etc.
This can be written and debugged in a few hours. It would take as long to set up a parser for C without any functionality; that is you'd just have something which can read valid C but you'd still have to write the part of the parser which understands C, and the part which does something useful with the data.