Sign in to follow this  
Hammonjj

Unity C For The C++ Programmer

Recommended Posts

Does anyone know a resource for learning C as a C++ Programmer? My university teaches using C++, but there is an awesome intership opportunity I learned about recently, but they want someone who knows C. I know that they are similar, but is there a resource out there that teaches C to C++ people quickly? Thanks James

Share this post


Link to post
Share on other sites
C is basically C++ with everything good ripped out. Here's what you'd want to focus on:

1) No member functions. This is okay, everything is public, so just make them free functions with the first parameter as the "self".

2) No namespaces or overloading. You will be in wart central. ProjectSpecificPrefix_Verb_NounsDescribingTheOperationTarget tends to be a common pattern.

3) No virtual functions. Instead you have to roll your own using function pointers (and writing/maintaining your own vtables where appropriate), or switch()-hell.

4) No exceptions or RAII. Focusing on mantaining a single exit point -- and thus single cleanup section -- will help a lot for C. You can use goto to skip ahead to cleanup early on where you'd throw in C++. Get experienced with a leak detector, you're bound to miss things. All initialization and deinitialization will be manual, and error codes are going to be your error reporting mechanism.

5) No container classes or templates. Knowing how common data structures are immplemented is probably going to be needed -- you'll run into a lot of (re)implementations of it to maintain, chances are.

6) No single line comments, typedef struct { ... } name; instead of class name { ... };.

7) No new, only malloc. non-compile-time-constant-expression integral consts, get comfortable with enum as your replacement.

8) Chances are you're going to deal with ugly macros too. Know their common associated problems, since you'll run into those too.

9) Conversion errors are demoted to warnings for all sorts of henious shit. Know your compiler's "treat warnings as errors" flag, and pray your existing codebases will compile with it.

10) Know your bitwise operations. C programmers love em to death.



Since C++ started out as a strict superset of C (and still largely is), the specific alternatives you'll be using will actually work in both languages.

Share this post


Link to post
Share on other sites
I would add:

  • In particular, no std::string, but an entire string.h header for handling functions, and all the idioms involved in writing decently fast and well-behaved non-trivial code with C-style strings (definitely not easy).

  • The callback-and-void* paradigm, where you provide a void* pointer to something along with a callback in order to simulate a closure.

  • No references, you have to pass pointers instead. Possibly use T* p and T p[] to distinguish pass-by-reference arguments from array arguments.

  • Massively procedural code. Writing object-oriented code is possible in C, but definitely not easy, so it might sometimes be far better to achieve modularity through procedural means instead.

Share this post


Link to post
Share on other sites
C has got realloc, allowing you to resize the size of a buffer or array. AFAIK, C++ has no equivalent in its new/delete syntax to do this as easily.

But C++ has the std::containers so it's not really a problem either.

So to the above list to add:

  • No std::containers

Share this post


Link to post
Share on other sites
// This is malloced by func_alloc, and released by 
// func_dealloc, unless we encounter an error func_a, func_b,
// func_c, then you need to release it manually. You need to re-allocate
// it manually by calling func_realloc if you switch the mgm_data_file_c
// on linux, but not on Solaris.





Of course, pray that such comments will actually be in the code. And reflect what needs to be done.

Lots of pointer magic.
Lots of conditional allocations.
Completely unsafe memory and array access. What? Programmer should know that p_data_28_bytes will always alocate 17 bytes.

C is evil. And then you enter the world of embedded programming and drivers.

That better be one helluva job.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
C is basically C++ with everything good ripped out. Here's what you'd want to focus on:

1) No member functions. This is okay, everything is public, so just make them free functions with the first parameter as the "self".



Can be emulated with some pointer magic + static function definitions.

[quote]

Quote:

3) No virtual functions. Instead you have to roll your own using function pointers (and writing/maintaining your own vtables where appropriate), or switch()-hell.


See above (that's why you can compile DirectX on C). But I agree, this can be a hard trip if you're not familiar with this (I make usage of that in my ray tracer. Not that I can't use c++, writing the whole thing in C in an object oriented manner was just one thing I always wanted to do, yay :D )

Quote:

6) No single line comments, typedef struct { ... } name; instead of class name { ... };.


oh oh, C99

Quote:

10) Know your bitwise operations. C programmers love em to death.


yes :D

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
I would add:

  • In particular, no std::string, but an entire string.h header for handling functions, and all the idioms involved in writing decently fast and well-behaved non-trivial code with C-style strings (definitely not easy).

  • The callback-and-void* paradigm, where you provide a void* pointer to something along with a callback in order to simulate a closure.

  • No references, you have to pass pointers instead. Possibly use T* p and T p[] to distinguish pass-by-reference arguments from array arguments.

  • Massively procedural code. Writing object-oriented code is possible in C, but definitely not easy, so it might sometimes be far better to achieve modularity through procedural means instead.


Good points.

Quote:
Original post by Lode
So to the above list to add:

  • No std::containers


This is what I meant with #5.

Quote:
Original post by greenhybrid
Quote:
Original post by MaulingMonkey
C is basically C++ with everything good ripped out. Here's what you'd want to focus on:

1) No member functions. This is okay, everything is public, so just make them free functions with the first parameter as the "self".



Can be emulated with some pointer magic + static function definitions.


No need for pointer "magic" (just a normal pointer for an explicit "this" argument for the aforementioned static/free function), unless you meant for implementing virtual functions, in which case given I give two example emulation mechanisms right in #3, well, yeah. I can't say I disagree.

Your C99 link also indirectly raises a couple extra points to add to the list though:

N) Predeclaring your variables instead of declaring them at use point.
N+1) va_args. No operator chaining to bail you out from this in C. (Reminded from the mention of vardaric macros, even if unrelated). Hope your compiler can warn with format string/argument list mismatches...
N+2) Be ready to cry a lot whenever you think of any other language and all the wonderful tools they have that you can't use.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
4) No exceptions or RAII. Focusing on mantaining a single exit point -- and thus single cleanup section -- will help a lot for C. You can use goto to skip ahead to cleanup early on where you'd throw in C++. Get experienced with a leak detector, you're bound to miss things. All initialization and deinitialization will be manual, and error codes are going to be your error reporting mechanism.


That's not quite accurate with regard to exceptions. While the standard doesn't stipulate an exception mechanism, various compilers do. For example, Microsoft provides "try-except" and "try-finally" forms under the grouping of "Structured Exception Handling" and many other vendors follow that pattern. However, no vendor provides exception objects that can be thrown and caught ala C++.

Share this post


Link to post
Share on other sites
MSVC++ (Including the express versions) can be set to compile code as C instead of C++. This takes care of all the places where valid C isn't actually valid C++. (It's not C99 though...)

Share this post


Link to post
Share on other sites
There are some nice perks in C (99). Designated initializers and variadic macros are among my favorite features. Void pointer casting is implicit. There's no name mangling to worry about. Here's a detailed list of differences between C and C++.

Share this post


Link to post
Share on other sites
Although I do most of my coding these days in C++ or more recently, Java, I really enjoy C. It is simple, straightforward, and if used properly, can be extremely readable and fun to program in. Best of luck!

Share this post


Link to post
Share on other sites
You can do exception-lite in C with setjmp/longjmp. Which is what __try and __finally expand to anyway, if I recall correctly (certainly TRY and EXCEPT do).

Try coding in Symbian OS, C++ with extra C style paranoia. Oh my!

Share this post


Link to post
Share on other sites
The thread seems to be about differences in the syntax of the language, and overlooking that there is a completely different thought process in C and C++.

Both languages have had two major updates to the ISO standards and have diverged from their common ancestry (the C89 standard). C's last update was in 2004, c++ in 2003, and both have additional changes in the works. C++ isn't just "C with extra stuff", nor is C just "C++ with the good stuff ripped out", they are both distinct languages with their own ISO standards.


Well-written c++ code relies heavily on things like the STL, virtual functions, and inheritance chains. These features do not exist in c, although you can fudge them in if you try. Your main goal in C++ is to specialize out a solution from something that mostly works, promote specialized behavior when it is common, and rely heavily on abstractions.

Well-written c code does a lot of things that are very illegal in c++. These include implicit casting, implicit declarations, and direct object initialization. Many well-written C applications and libraries rely on const correctness to a far greater degree than their c++ counterparts, which can be another learning curve when starting out. Your main goal in C is to operate on structures in a more general way, adding independent functionality as separate entities rather than inter-related specialized parts. It relies less on abstracted code and more on direct manipulation.


In short, it isn't just about syntax, it is a different methodology.

Share this post


Link to post
Share on other sites
Quote:
Original post by Lode
C has got realloc, allowing you to resize the size of a buffer or array. AFAIK, C++ has no equivalent in its new/delete syntax to do this as easily.

Don't use this code, but this is basically how realloc would work in C++.

template <typename T>
T *CPlusPlusRealloc(T *ptr) { T *np=new T(*ptr);delete ptr;return np; }

template <typename T>
T *CPlusPlusReallocN(T *ptr,size_t n)
{
T *np=new T[n];
std::copy(ptr,ptr+n,np);
delete[] ptr;
return np;
}




C is evil and I hope I never have to go back to it. I'm done with the world of no smart pointers.

Share this post


Link to post
Share on other sites
Quote:
Original post by frob
It relies less on abstracted code and more on direct manipulation.

You can do that just as easily in C++ as in C, the only reason why it is discouraged in C++ is that C++ has better alternatives. Alternatives such as better support for abstractions and encapsulation.

You can apply C thinking to C++ but you won't be using its full potential. You can try to apply C++ thinking to C but there's only so much that could emulate that way.

They are different languages with different approaches, but C++ covers most of what C can effectively be used for. Given that the availability of compilers isn't a problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by T1Oracle
Quote:
Original post by frob
It relies less on abstracted code and more on direct manipulation.

You can do that just as easily in C++ as in C, the only reason why it is discouraged in C++ is that C++ has better alternatives. Alternatives such as better support for abstractions and encapsulation.

You can apply C thinking to C++ but you won't be using its full potential. You can try to apply C++ thinking to C but there's only so much that could emulate that way.

They are different languages with different approaches, but C++ covers most of what C can effectively be used for. Given that the availability of compilers isn't a problem.


That was exactly the point I was trying to make in my comment.

Yes you can emulate one language's approach using the other, but acknowledging that fact means you implicitly acknowledge they use different approaches.

The OP was asking about what is involved with learning it as an additional language, not the availability of compilers.

Share this post


Link to post
Share on other sites
Learning C as a C++ programmer is easy, in my opinion. Here's a quick sketch of differences:

* No classes. Structs can't have constructors or member functions.

* Everything that is a struct must be prefixed with "struct", every time it is declared as a variable or in a parameter list. C programmers fix this by using typedefs: typedef struct tagMYSTRUCT MYSTRUCT; Then MYSTRUCT is enough to declare a struct var.

* No references, only pointers.

* No STL. You want dynamic arrays, write code yourself every time, or write a series of reusable functions to minimize code duplication, and therefore a margin for error.

* No single-line comments, unless you are using Pelles C IDE, which is what I use for C development.

* If you are using COM functions, you are in for some fun. You have to call global versions of interface functions explicitly and pass the interface pointer to them, instead of familiar C++ way of simply using -> to refer to COM interface functions.

Well, I think that's about it. I wrote two medium size programs in C, one of them was a database consisting of several files. I used windows functions such as CreateFile for file I/O since the beginning of time, so I didn't notice the absence of file streams. I also typically use malloc/realloc/free in C++ instead of new, so I didn't notice the absence of new either.

Share this post


Link to post
Share on other sites
Quote:
You can try to apply C++ thinking to C but there's only so much that could emulate that way.
Actually, there is nothing C++ can do that you can't 'emulate' with C. The first C++ compiler actually compiled to C code.

Share this post


Link to post
Share on other sites
For some fine-tuning of advanced understanding about C/C++ differences go to http://david.tribble.com/text/cdiffs.htm

The rest is pretty obvious... mostly everything involving objects is not present in C.

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
Quote:
You can try to apply C++ thinking to C but there's only so much that could emulate that way.
Actually, there is nothing C++ can do that you can't 'emulate' with C. The first C++ compiler actually compiled to C code.


Templates~~

Share this post


Link to post
Share on other sites
Quote:
Original post by Konfusius
Quote:
Original post by Deyja
Quote:
You can try to apply C++ thinking to C but there's only so much that could emulate that way.
Actually, there is nothing C++ can do that you can't 'emulate' with C. The first C++ compiler actually compiled to C code.


Templates~~


Macros~~!!


#define DECL_VECTOR(T) typedef struct Vector_ ## T ## _ { \
T* data; \
size_t size; \
} Vector_ ## T ; \
\
void Vector_ ## T ## _Init ( Vector_ ## T * vector, size_t size=0 ); \
void Vector_ ## T ## _Done ( Vector_ ## T * vector ); \
void Vector_ ## T ## _Push_Back( Vector_ ## T * vector, T element ); \
T* Vector_ ## T ## _At ( Vector_ ## T * vector, size_t index ); \
T* Vector_ ## T ## _Begin ( Vector_ ## T * vector ); \
T* Vector_ ## T ## _End ( Vector_ ## T * vector ); \
/* End of DECL_VECTOR */



#define DEFINE_VECTOR(T) \
DECL_VECTOR(T) \
void Vector_ ## T ## _Init( Vector_ ## T * vector, size_t size ) { \
vector->data = (T*)malloc( sizeof(T) * size ); \
vector->size = size; \
} \
void Vector_ ## T ## _Done( Vector_ ## T * vector ) { \
free( (void*) vector->data ); \
vector->size = 0; \
} \
void Vector_ ## T ## _Push_Back( Vector_ ## T * vector ) { \
T* next_ = (T*)realloc( (void*)vector->data , sizeof(T) * (vector->size+1) ); \
assert( next_ ); \
vector->data = next_; \
vector->size += 1; \
} \
T* Vector_ ## T ## _At( Vector_ ## T * vector, size_t index ) { \
assert( index < vector->size ); \
return vector->data + index; \
} \
T* Vector_ ## T ## _Begin( Vector_ ## T * vector ) { \
return vector->data; \
} \
T* Vector_ ## T ## _End( Vector_ ## T * vector ) { \
return vector->data + vector_size; \
} \
/* End of DEFINE_VECTOR */



DEFINE_VECTOR(int)
DEFINE_VECTOR(float)

int main() {
Vector_int integers;
Vector_float reals;

Vector_int_Init( &integers );
Vector_float_Init( &reals );

Vector_int_Push_Back( &integers, 1 );
Vector_int_Push_Back( &integers, 2 );
Vector_int_Push_Back( &integers, 3 );
Vector_float_Push_Back( &reals, 1.0f );
Vector_float_Push_Back( &reals, 2.0f );
Vector_float_Push_Back( &reals, 3.141592653589f );
}



This is a simple example --- using all the nasty cast tricks available to you, it's quite possible to get much, much more evil :D

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this