Switching from C++ to C: any suggestions?

Started by
21 comments, last by ravyne2001 17 years, 6 months ago
I've just joined my high school's FIRST robotics team, and I'm in the programming group. We *have* to use C, not C++, because, well, I'm not 100% sure, but it's either that there's no C++ compiler for this processor, or that the rules require us to for some reason. Suffice it to say that this is out of my control. So, is there anything I should keep in mind comming from an almost entirely C++ background? I know about the obvious differences, like not having templates, classes, having to declare variables at the start of the scope, and much of the standard library, but I don't know much more than that. Any common mistakes or such for a C++ programmer to make in C? Thanks in advanced.
Advertisement
Well, I've done it before. The biggest mistake is to try and emulate C++ things in C. You have to fully adapt. Apart from that, there's not a lot else, just be a lot more careful with your dynamic memory allocations.
[ search: google ][ programming: msdn | boost | opengl ][ languages: nihongo ]
about every second line should include an assertion. assert everything!!!111
working with raw pointers and especially void-pointers all the time is pretty much the biggest source of errors in C, so do absolutely everything to find errors there as soon as possible, otherwise complete frustration is guaranteed.
------------------------------------------------------------Jawohl, Herr Oberst!
Quote:Original post by Ezbez
I've just joined my high school's FIRST robotics team, and I'm in the programming group. We *have* to use C, not C++, because, well, I'm not 100% sure, but it's either that there's no C++ compiler for this processor, or that the rules require us to for some reason. Suffice it to say that this is out of my control.

So, is there anything I should keep in mind comming from an almost entirely C++ background? I know about the obvious differences, like not having templates, classes, having to declare variables at the start of the scope, and much of the standard library, but I don't know much more than that. Any common mistakes or such for a C++ programmer to make in C?

Thanks in advanced.


C is just easier than C++. There are some difference in the standard library, struct are no longer classes (because there is no classes) and can no longer be defined using the C++ syntax - a typical usage is to typedef an unnamed struct to a type name:
typedef struct{  int field1;  int field2;} MyStructName;

However, there are some other strange things this notation: since you didn't defined the type yet, you can't use it in the structure itself.
typedef struct{  ListElem *next;  ListElem *prev;} ListElem;

Is invalid. It have to be either
typedef struct list_elem_t ListElem;struct list_elem_t{  ListElem *next;  ListElem *prev;};

Or
typedef struct list_elem_t{  struct list_elem_t *next;  struct list_elem_t *prev;} ListElem;

You must typedef enum too (if you plan to use MyEnum instead of "enum my_enum") This is the biggest syntax difference I know of.

The C++ draft here (pdf) has a Compatibility annex with some of the most notable differences between C and C++. It is worth a look.

HTH,
Quote:We *have* to use C, not C++, because, well, I'm not 100% sure, but it's either that there's no C++ compiler for this processor, or that the rules require us to for some reason. Suffice it to say that this is out of my control.


I don't know what kind of hardware you're using but lots of embedded platforms only have c compilers available. Which is probably the reason you have to use C.

You shouldn't have too many problems, I doubt you're going to be writing all that much code you'll spend more time on coming up with good algorithms getting the hardware working, sorting out mechanics etc.
If you're dealing with a processor that doesn't have a C++ compiler, then odds are it's C compiler isn't that great either so don't rely on behaviour in C99.

* Watch you're casting!! C is far, far too forgiving when it comes to type checking.

* There's no reason you can't do object-oriented programming in plain old C. You can even do inheritence and polymorphism.
typedef struct{    void (*destroy)(Object*);    bool (*update)(Object*, int);} Object;void destroyObject(Object* obj){    obj->destroy(obj);    free(obj);}void updateObject(Object* obj){    obj->update(obj);}typedef struct{    Object obj;    Vertex *vertices;} Model;Object* createModel(int numVerts){    Model *this = malloc(sizeof(Model));    this->obj.destroy = &Model_destroy;    this->obj.update = &Model_update;    this->vertices = malloc(sizeof(Vertex)*numVerts);    return &this->obj;}void Model_destroy(Model* this){    free(this->vertices);}void Model_update(Model* update){    // Do stuff with vertices}void doStuff(){    Object *obj;    obj = Model_create(10);    updateObject(obj);    destroyObject(obj);}


* Make sure you've got function prototypes, because older C compilers won't even warn you about not providing them. They'll gladly let you do the following:

int func1()
{
return func2(10);
}

int func2(int a, int b)
{
return a + b;
}


* Check if you're processor is 16-bit or 32-bit (or *shudder*...8-bit!). If it's not 32-bit then you'll have to keep an eye on your integer arithmetic because an 'int' will only be 16-bit (longs are usually still 32-bit though but no guarenttees, check your compiler documentation).

* Your CPU probably doesn't have floating-point support (although it might be emulated)
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
Naming things is a bit of a pain in C as well, due to the lack of namespaces etc. I've found when I've been forced to use C, I need to split things up into a lot more translation units than C++ in order to hide implementation details and so on.

You can also end up relying on the preprocessor a lot more which is possibly the most common cause of hard-to-track bugs and errors.
for any non-trivial project, it might in fact be more feasible to simply port the processor/architecture to gcc, so that it is supported as a new backend by the compiler, this will usually provide with language support for ALL gcc frontends (c, c++, ada, fortran, java etc). Also, adding new backends to gcc has meanwhile become a relatively straight forward thing to do, there's good documentation available for most architectures, porting comes down to copying/pasting the corresponding passages from other targets. gcc has in fact become a pretty viable compiler framework to be used even for embedded platforms, there are for example ATMEL targets and even PIC targets (or patches) available for gcc.

And even if you should decide not to use gcc and to definitely use a corresponding embedded C compiler, you may still want to consider using C++ as the programming language, if you check out the gcc-patches mailing list, you'll find a patch that allows arbitrary frontend code translated from RTL to C, that way you can have anything converted to (UGLY) C, but still C.

However, this may only be feasible if you have to manage a truly non-trivial project, which C is certainly not the most ideal language for, which is also heavily illustrated by the gcc project itself.
- Learn about function pointers.
- Learn about the volatile keyword. If you're writing C to talk to hardware, you will inevitably be reading data from pins and sensors, meaning you don't want it to be cached - everytime you read it, it has to be the correct, current value. I'm sure they'll drill you about this on your first day anyway.

Have fun!
The main difference for me was that you have to pass a pointer to your data structs instead of just using a class.

For example in C++:

class MyClass{public:  MyClass( int a ) : m_MyData(a) { }    void DoSomething();  int DoSomethingElse( int a );  int m_MyData;}//MyClass *c = new MyClass( 5 );c->DoSomething();int r = c->DoSomethingElse( 10 );delete c;


You have something such as:-

struct MyData{  int MyData;};MyData *MyDataCreate(){  MyData *r = (MyData*)malloc( sizeof(MyData) );}void MyDataDestroy( MyData *a_data ){  free( a_data );}void MyDataDoSomething( MyData *a_data ){  // Blah}int MyDataDoSomethingElse( MyData *a_data, int a ){  a_data->MyData += a;  return a_data->MyData;}// MyData *d = MyDataCreate();MyDataDoSomething( d );int r = MyDataDoSomethingElse( d, 10 );MyDataDestroy(d);


I actually found it easier to encapulate systems in C than in C++ - even with the Object-oriented paradigm but that's maybe because I just suck at C++ sometimes ;) I find that I'm better able to define my interfaces when using C, I don't know why - I think the act of keeping everything in separate header files and distinguishing them as public/private seems more intuitive than having a class.

This topic is closed to new replies.

Advertisement