Is there something that I can do in C but I can't do in C++? [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last month.
Improve this question
Is there something that I can do in C but I can't do in C++ ?
I stumbled upon the question in a sample interview questions site.

Declare a variable named 'class', as in:
int class = 0;

...that is there anything I can do in C but not in C++.
Both languages are Turing complete, so in theory you can code up equally functional applications in both.
OTOH, C++ is not a superset of C. Especially C99 has some features that C++ does not have. E.g. designated initializers, variable length arrays in structs and as automatic variables. Depending on your "anything", this could be something that C++ cannot do but C can.

In C, you can create array literals ("compound literal"), but in C++ you cannot
/* p points to the first element of an array of 4 int */
int *p = (int[]){1, 2, 3, 4};
You can also create an array with size not yet known at compile time, but C++ has no such possibility ("variable length array"):
// create array. size is known at runtime only.
int p[rand() % 5 + 1];

int new = 0;
works in C, but obviously can't work in C++ because 'new' is a reserved word.
There are some other 'tricks' with reserved words, but other than that, you can pretty much do everything in C that you can do in C++.

Quite a few things. For example, in C you can write code like this:
void * v = 0;
char * p = v;
and you can create arrays like this:
int main() {
int n = 42;
int a[n];
return 0;
}
neither of which will compile under C++.

C++ lacks C99's restrict qualifier. Therefore, there is no way to tell the compiler to perform optimizations based around knowing that pointers aren't aliases.

There are some things you can say in C wihch you can't in C++ (because C++ has stricter syntax-checking, and C has a more extensive 'legacy' syntax).
Also, there may be some run-time environments (O/S+library+compiler) which support C but not C++, so you can do C on those platforms where you can't do C++.

Syntactically there are a few things you could write in C that wouldn't compile in C++ (See Incompatibilities Between ISO C and ISO C++ for excruciating details.). If you're asking at a higher level, if there is some program that it's possible to write in C, but not possible to write in C++, then the answer is "No."

Actually, I can think of one example:
When you create a library (.lib file or .dll file) to be shared by other applications, you're better off using C instead of C++ because the results are more portable. You can do this within a C++ compiler by using an 'extern "C"' block though.
Specifically, C++ has a quirk where there is no standard convention for name mangling - for translating your library's function signatures into more low level names used by the compiler. So for example if you have a function like 'int addNumbers (int a, int b)', different C++ compilers may translate this function into different names, which can lead to problems when you want to import the library. If you use a C compiler or surround your library importing and exporting code with a C block though you won't see this problem, since there is only one way to mangle function names in C.

In 'C' you don't need forward declarations. This allows you to pass parameters which are interpreted incorrectly. (Not that this is a great feature, but you can't do it in C++)
in file A:
float sum(float a, float b)
{
return a+b;
}
in file B
main()
{
printf("%f\n", sum(1,2));
}
with C, this compiles, but prints 0.000
with C++, you need a float sum(float,float); before the printf, and it gives the expected result.

You can sparsely initialize arrays in C. I like to use it for mapping int->sometype for relatively dense static maps where an unmapped value can be interpreted as 0:
int my_array[] = { [1] = 3, [4] = 2 };
printf("%d %d %d\n", sizeof my_array, my_array[0], my_array[1]);
/* prints 20, 0, 3 */

The 1998 C++ standard has a list of incompatibilities with the 1990 C standard that is 13 pages long (Annex C). Granted, it's not a lot, compared to the amount of pages that describe the languages, but still covers quit a bit of ground.
Quick summary of the kind of differences that it lists:
New keywords are added (any C program that uses them as identifiers is not C++)
Type of character literal changed from int to char (compare sizeof('a') in C and C++!)
String literals made const (can't do char* q = expr ? "abc" : "de";)
"Tentative definitions" are removed from the language.
"Compatible types" are removed from the language.
Converting from void* to any other pointer now requires casting.
Converting from any const/volatile pointer to void* now requires casting.
"Implicit declarations" are removed from the language.
Expressions can no longer create new types (as in p = (void*)(struct x {int i;} *)0; )
results of some expressions became lvalues (compare sizeof(0, arr) for char arr[100];)
...that was the first 3 pages of Annex C.
If you go to the 1999 C standard, the differences are going to take forever to describe. Although C++0x did include some of C99 features, many of them are just inherently incompatible, like the complex type.

In C, you can declare variables with the following names:
bool, class, new, delete, template, typename, this, throw, catch,
typeid, operator, virtual, static_cast, reinterpret_cast,
dynamic_cast, mutable, public, private, protected, friend; //many more
then you can do these:
int namespace = private + protected + public;
int decltype = static_cast + dynamic_cast + reinterpret_cast;
int constexpr = (new + delete) * (template + typename);
All of them are keywords in C++11.

You can do almost everything in any of the programming languages. Of course the way of expressing it will vary, as well as the amount of code, clarity of code, ease of further maintenance. Some tasks can be coded with few lines in Prolog and few pages of code in C++, and so on.
Some limiting factors are the available libraries, available compilers, and low-level issues. However when you consider C and C++ on a typical PC, then there is no difference in things that can be done in either of them.
Unless of course you were asking for the differences between C and C++ - for these other people have given you the idea.

char *c = malloc(sizeof(char));
is valid in C, not C++ i.e. automatically casting void*. This of course is a syntax issue, not so much as what you can and cannot _do_ (i.e. accomplish).

If the criteria is to solve a particular programming problem then both will do the job although it may be a bit easier in some cases to do it in C++ due to the higher level of abstraction

Is this referring to the latest C standard? The original C standard (ANSI 1989 or ISO 1990, with 1995 updates) is fairly close to being a subset of C++. There's differences, but they're mostly contrived (the biggest exception probably being that void * converts freely with any data pointer in C but not in C++).
However, a new C standard came out in 1999, some time after I'd stopped doing anything in the most modern C. It had new features, some of which are going into the C++ standard due this year or next, but not all.

C++ is obviously not a superset of C for a very simple reason: New keywords have been added to C++
class, virtual, new, etc and thus can no more be used as identifiers in C++.
Some of the reasons are subtler.
You can find an exhaustive answer to this question on Bjarn Stroustrup's website:
The C++ programming language | Appendix B

C can have a function with an unspecified amount of arguments. Disclaimer that this is bad practice and shouldn't be used, but present and interesting nonetheless:
void x() { }
in C means a function with an unspecified amount of parameters. This is as opposed to
void x(void) { }
Which means a function with 0 parameters in C. In C++ both functions mean the same thing and take 0 arguments.
Using the unspecified parameter count in C, you could access the parameters the same way you would using variable arguments.
So:
void x()
{
}
int main()
{
// This line would compile in C and C++
x();
// This line compiles in C but not C++
x(5, 7)
return 0;
}
That is why you should try to write void as a parameter instead of leaving them blank. In C always explicitly write void so you don't have issues, and inC++ both are equivalent so it doesn't matter but it's nice to be explicit.

Many aspects of hardware-related embedded ("freestanding") systems programming are only possible in C.
[Major difference] In C you can do union type punning, which is done is pretty much every professional microcontroller hardware peripheral register map ever written. This is undefined behavior in C++.
In C you can use the de facto standard freestanding implementation-defined form of main() as void main (void). This is not allowed in C++ because of artificial restrictions. You must either have your bare metal C++ program return a value to la-la-land or name the procedure entered at startup something else than main.
When using structs allocated with static storage duration in C, you can have them quickly initialized with just a "zero out" (.bss initialization). Doing the same in C++ with structs/classes will mean that member variables get "zeroed out" too, but in addition default constructors will get called, leading to needlessly slow program startup.
[Major difference] In C you can declare const variables without initializing them. This is very useful for const volatile variables declared in EEPROM/flash, to be written to in run-time by bootloaders and similar. In C++ you are forced to initialize the variables, which in turn forces default values to get burned into EEPROM/flash, leading to slower programming time and slightly more physical memory wear.
[Major difference] No standard library function in C performs heap allocation silently/implicitly, apart from the malloc family (and in C23, strdup as well). In C++, silent heap allocation is very common in standard library functions, making those libraries unsuitable for embedded systems.
restrict pointers are possible to use in C for various micro-optimizations.
C allows pointers to VLA, which can help improving readability and diagnostics. On the other hand, C++ doesn't allow objects of VLA type, which is a good thing in embedded systems. C compilers can optionally refuse to implement certain aspects of VLA depending on their standard compliance (C99 vs C11/C17 vs C23 - C23 being the most suitable for embedded systems in regards of VLA).
C++ didn't support designated initializers until C++20 and these are quite handy to have in all manner of situations. (C++ does support initializer lists with named members inside constructors, however.)
C doesn't allow exception handling and I'd say that's a huge benefit in embedded systems. You'll want to avoid opening that can of worms inside your deterministic firmware. Error handling in C is rather handled gracefully by returning an error code from one module to its caller and then further down the line as needed. Instead of violently crashing down the dependency chain if left unhandled, just like the average run-away code bug would. It is however possible to write exception-free code in C++ too, if done with great care.
(Major) "Forever loops" is an important concept in programming, particularly so in embedded systems programming, where even empty loops with no side effects are common. And yet C++ doesn't support that. Optimizing away a "while(1);" in C++0x. A perfectly valid embedded systems program might look like init_interrupts(); for(;;){}. However, the C++ committee have apparently not taken such very common scenarios in consideration, so you can't write such programs in C++.
Benefits of C++ over C in hardware-related programming:
Inline assembler is standardized in C++, since C++ predicted that the programs written in it would get executed on computers. C did make no such prediction and so inline assembler/running your C program on a computer is not yet supported even in C23. It's just sad. (Similarly sad, neither language has a standardized interrupt keyword.)
C++ historically has a much better system for static assertions than C, which didn't support them proper until C11 (and further support is added in C23).
C++ guarantees a diagnostic message when doing implicit pointer conversions to/from void*. C does not. And void pointers are generally to be avoided in embedded systems.
You cannot call main() recursively in C++.
Conditional expressions with logic/relational/equality operators in C++ result in bool.
Character constants ('A') are of type char in C++, which saves a tiny bit of memory.

"If it can't be done in assembly, it's not worth doing!"
ok, humor aside, I THINK the OP is asking syntactically, rather than operationally.
I think that there are a few obscure things that are legal in C (at least C89) that are not legal in C++, or at least deprecated... But (if they exist) they're pretty obscure. C++ is functionally a superset of C.

C++ does not support named struct member initialization but in C you can do:
struct { int x, y; } a = { .x = 3 };
You can also combine this with the feature shown by Matt Havener:
struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2 };

The short answer is...no, not really. See http://www.research.att.com/~bs/bs_faq.html#difference

Related

Should I stop using the term C/C++? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
I understand C and C++ are different languages but when I was learning C++ I was always told that C is a subset of C++ or C++ is C with classes. And that was quiet true until the appearance of C++x0, C++11 (or the modern C++ 11/14/17 in general). In fact (specially when working on embedded systems) it's very likely to find code written in C++ but with a lot of parts written entirely in pure C language. Here I have several questions:
Should I stop using the term C/C++?
If the answer to #1 is yes, how would I call a program that use a mix of C and C++?
Given that both of them are 'different' languages is it likely that at some point C++ compilers stop supporting code written in the C language (since modern c++ is diverging from the C mentality for basic stuff like pointers, dynamic memory handling, etc)
Is there right now any collaboration between the people who makes the standards of C/C++ to keep the compatibility
If #4 is yes, such collaboration could end up in the near future with the appearance of the modern c++ (11/14/17)
I know that there already similar questions, but I'm sure that a lot of people share these doubts so I'm very interested to get good answers specially for the points that have to do with the C++ tendency in the near future.
C was never a subset of C++. The most obvious example of this is int new;. This has been true since C89 and C++98, and the languages have only grown further from each other as new standards have come out.
Should I stop using the term C/C++
Yes
If the answer to #1 is yes, how would I call a program that use a mix of C and C++?
A source file is written in one language or the other. A program can consist of code from multiple languages working together, or an executable produced by linking different compiled objects. You would say the program was written in C and C++, "C/C++" is not a language.
Given that both of them are 'different' languages is it likely that at some point C++ compilers stop supporting code written in the C language
3) They never did. int *a = malloc(10);. C and C++ have long since diverged. click the links or see below for a file that is fine with C89 and up, but isn't valid under any C++ standard.
4) afaik no, the working groups are aware of each other but the standards make the decisions that are best for themselves.
/* A bunch of code that compiles and runs under C89 but fails under any C++ */
/* type aliases and struct names occupy separate namespaces in C, not in C++ */
struct S { int i; };
typedef int S;
struct Outer { struct Inner { int i; } in; };
/* struct Inner will be Outer::Inner in C++ due to name scope */
struct Inner inner;
/* default return type of int in C, C++ functions need explicit return types */
g() {
return 0;
}
/* C sees this as two declarations of the same integer,
* C++ sees it as redefinition */
int n;
int n;
/* K&R style argument type declarations */
void h(i) int i; { }
/* struct type declaration in return type */
struct S2{int a;} j(void) { struct S2 s = {1}; return s; }
/* struct type declaration in argument, stupid and useless, but valid */
/*void dumb(struct S3{int a;} s) { } */
/* enum/int assignment */
enum E{A, B};
enum E e = 1;
void k() {
goto label; /* C allows jumping past an initialization */
{
int x = 0;
label:
x = 1;
}
}
/* () in declaration means unspecified number of arguments in C, the definition
* can take any number of arguments,
* but means the same as (void) in C++ (definition below main) */
void f();
int main(void) {
f(1); /* doesn't match declaration in C++ */
{
/* new is a keyword in C++ */
int new = 0;
}
/* no stdio.h include results in implicit definiton in C. However,
* as long as a matching function is found at link-time, it's fine.
* C++ requires a declaration for all called functions */
puts("C is not C++");
{
int *ip;
void *vp = 0;
ip = vp; /* cast required in C++, not in C */
}
return 0;
}
/* matches declaration in C, not in C++ */
void f(int i) { }
I always feel it's worth mentioning that C is a subset of Objective-C.
I was always told that C is a subset of C++ or C++ is C with classes. And that was quiet true until the appearance of C++x0, C++11 (or the modern C++ 11/14/17 in general).
C has never been a subset of C++. For example C89 is not a subset of C++98.
A few examples:
the C89 identifier-list form for function parameter declaration is not supported in C++
C89 and C++98 have different types for the characters constants
C89 and C++98 have different types for string literals
logical operators yield different types in C89 and C++98 (int vs bool)
Should I stop using the term C/C++?
Yes.
If the answer to #1 is yes, how would I call a program that use a mix of C and C++?
A program is either C or C++ (if even some very basic program can compiled with either a C or a C++ compiler). What compiler are you using to compile it? It should answer your question. Harbison & Steele coined the term Clean C to designate a common subset of C and C++ but I think it was a bad idea.
EDIT: However I admit that technically you can link C and C++ objects files in a single program but OTH there are many languages that are allowed to be mixed in a single program for example Java and C++. I think using the term C/C++ program only adds to the confusion that it is written in a single language called C/C++.
Given that both of them are 'different' languages is it likely that at some point C++ compilers stop supporting code written in the C language (since modern c++ is diverging from the C mentality for basic stuff like pointers, dynamic memory handling, etc)
There are many features (example: variable length array, flexible array member, _Generic, ...) of C99 or C11 that are not supported by any C++ version.
In general the SO users ask the person who is asking the question to choose a language: C or C++. Why?
There are many subtle differences between C and C++. For example, in C++, a const variable at global scope has internal linkage unless declared extern, but in C it has external linkage unless declared static. By saying "C/C++", the OP is asserting knowledge that the answer to their question is the same in both C and C++, when it very well might not be. This needlessly makes things harder for would-be answerers.
Sometimes we can spot that the code isn't valid in one language or the other (for example, implicit conversions from void* to pointer to object are not valid in C++). This is annoying. Why are you saying "C/C++" when you have a piece of code that's valid in C but not C++? Did you intend C, or is this just an error in code intended to be C++?
Sometimes the answer will be different depending on the language (for example, variable-length arrays exist in C99 but not in C++). If we don't know what language you're talking about, either we have to guess, or write an answer for both when only one will actually be useful, because you know which language you're actually using; you're just not telling us!
Sometimes the answer really is the same for both languages, but it's hard to be sure. For example, I think C and C++ have the same integer conversion rules, but in order to be really, really sure, I have to read both standards carefully. Again, this makes me do twice as much work as necessary when you probably only care about one of the languages.
Anyway, to answer your other questions:
Yes.
If you are linking together C and C++ code, it is acceptable to use both tags, but please specify which language each file is in.
There are breaking changes sometimes, but they're rare and typically limited in impact (otherwise they don't get approved). For example, auto in C++11.
I don't think they directly collaborate, but they pay attention to developments in the other language and try to avoid introducing changes that would make compatibility more difficult.
And if you really do want to know about both languages, that's fine, and you can say that in your question. When you say "C/C++", I'm really not sure what you mean, and it really looks like you're making an assumption about the two languages.

Does C++ contain the entire C language? [duplicate]

This question already has answers here:
Where is C not a subset of C++? [closed]
(11 answers)
Closed 7 years ago.
I have read in tutorials that C++ contains the entire C programming language.
However I have also read, in places like this that
If you learn C++ you will eventually learn most of C with some differences between the languages that you will learn over time.
So my question is only this:
If I know C++ very well, will I eventually learn the "real" C language (without any "differences") because the full C90 language is included in C++11?
No, C++ is not a superset of the C language. While C++ contains a large part of C, there are subtle difference that can bite you badly where you least expect them. Here are some examples:
C has the concept of tentative definitions which doesn't exist in C++.
C does not require explicit conversion on assignment of void pointers to variables of concrete type.
C has different rules regarding const propagation.
C has something called the “implicit int rule,” which, although abolished with C99, appears some times and needs to be considered.
The C preprocessor has some features the C++ preprocessor does not have.
The C language has two styles of function definition, K&R-style and Stroustrup-style. C++ only has Stroustrup-style.
The lexing rules for C and C++ are different with neither being a subset of the other
C and C++ have different sets of reserved words. This can cause weird errors because an identifier is not allowed in the other language.
While C++ took almost all features from ANSI C (C89), many features were added to C in subsequent standard revisions that are not available in C++.
C++ has a different syntax, even for some parts that aren't new. For example, a ? b : c = d is a syntax error in C but parsed as a ? b : (c = d) in C++.
C guarantees that &*E is exactly identical to E, even if E is a null pointer. C++ has no such guarantee.
In C, a string literal initializing an array of characters can initialize an array that is at least as long as the string without the trailing \0 byte. (i.e. char foo[3] = "bar" is legal). In C++, the array has to be at least as long as the string including the trailing \0 byte.
In C, a character literal like 'A' has type int. In C++, it has type char.
C has a special rule to make type punning through unions to be legal. C++ lacks this language, making code such as
union intfloat {
int i;
float f;
} fi;
fi.f = 1.0;
printf("%d\n", fi.i);
undefined behaviour.
If I know C++ very well, will I eventually learn the "real" C language (without any "differences")
If you learn C++ properly, you will probably not need to use many of the standard techniques used in C. Theoretically you could program almost anything C in C++, with exceptions that have already been introduced. However, in reality, you wouldn't - or shouldn't. This is because C++ is a different language that provides a very different set of tools when used optimally.
Aside from the very basic elements like general syntax and fundamental types, these are two separately evolving languages, and they should be approached (learned, programmed) as such.
In broad terms, the C++ language is essentially C with a whole bunch of object oriented stuff added. Nearly all the code you could write in C will also compile and run just fine in C++.
However, there are a few corners of the languages where there are differences. The number of these have been slowly growing over time, but the languages aren't changing rapidly enough for that to be a significant problem.
If you only learn C++, then yes, you will eventually learn almost all aspects of the C language too. If you become expert in C++, then you will be able to identify and understand the places where small differences between the similar parts of C and C++ exist.
I am not sure what "differences" might exist...
For example like this one:
In C:
void foo() means "a function foo taking an unspecified number of arguments of unspecified type"
[...]
In C++:
void foo() means "a function foo taking no arguments"

Why is overloading not possible in C? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I know that overloading is not possible in C, and I want to know: why is overloading functions within the class and outside the class treated the same in C++?
Consider this case in C++ where the functions are declared outside the class:
foo()
foo(char c)
foo(int a, int b)
If C++ treats each function header as unique, why can't C do as well?
I think these might be the reason:
Function overloading was introduced in C++, so it is not available in C.
Polymorphism is an OOP concept, but C is not object-oriented.
Are there any reasons for the unavailability of function-overloading in C?
Perhaps the most important reason is the lack of prior art. There are very few examples of features added to C by the standard committee which have neither been popular extensions before nor are necessary to write strictly conforming code.
There is some vaguely defined "spirit of C", the C99 rationale (V5.10) reads (page 3, emph. mine):
Some of the facets of the spirit of C can be summarized in phrases like:
Trust the programmer.
Don't prevent the programmer from doing what needs to be done.
Keep the language small and simple.
Provide only one way to do an operation.
Make it fast, even if it is not guaranteed to be portable.
Further, C tries hard to stay backwards compatible with older revisions; old-style declarations, for example, have been marked obsolescent in C89 but are still part of C11. Ibid, page 2:
Existing code is important, existing implementations are not. A large body of C code exists
of considerable commercial value. Every attempt has been made to ensure that the bulk of this
code will be acceptable to any implementation conforming to the Standard. The C89 Committee
did not want to force most programmers to modify their C programs just to have them accepted
by a conforming translator.
Some differences in C and C++ are at least partly caused by function overloading, for example the type of character constants:
int foo(int);
int foo(char);
...
foo('x');
In C++, this calls foo(char), but in C, the type of 'x' is int, so either the result would be rather surprising, or 'x' needed to be of type char, possibly breaking existing code. Further, you probably want some promotions where they make sense, e.g. if in the last example, the second declaration of foo wasn't given, 'x' would be promoted to int and foo(int) was called. Such rules can become complex in detail (should void * be implicitly converted for function calls?). (Not a hard number, but the chapter about function overloading in the C++ standard (chapter 13) in the n3797 draft covers about 30 pages, chapter ibid. 5.2.2 about function calls is considerably longer than the corresponding C standard part.)
Pretty much every feature of C is necessary for a minimal language (well, modulo historic legacy), there is very little syntactic sugar; function overloading could be considered such (you could name your functions foo_int and foo_char etc and call the correct one explicitly).
The reasons you suggested, are circular (and thus aren't applicable): C did adopt some C++ features (e.g. function prototypes); and function overloading was introduced in C++ because C lacked it (you cannot say "It isn't part of C, because it's part of C++; and it's part of C++, because it isn't part of C"). Same goes for the second suggestion about C and OOP.
What I personally like about C is that it maps rather closely to the machine. It's often easy to see how assembler output generated from C code relates to it. The symbol names are unmangled and can be easily identified. The language is kept simple and minimal. Frankly, I don't understand what people are after when they want to see certain C++ features incorporated into C: We have C++, a language which offers those things, with the ability to write platform-specific, efficient code; why not just use it?
C11 introduced _Generic, which may be of interest for you.
You may find some interesting point in C99 rationale 7.22/25 Type-generic math
<tgmath.h> :
The ability to overload on integer as well as floating types would
have been useful for some functions, for example copysign. Overloading
with different numbers of arguments would have allowed reusing names,
for example remainder for remquo. However, these facilities would have
complicated the specification; and their natural consistent use, such
as for a floating abs or a two-argument atan, would have introduced
further inconsistencies with C89 for insufficient benefit.
Also C11 Standard introduced type _Generic macros, that allows to some sort of overloading, in sense that different types may be handled as function-like macros arguments.
I would say the first and foremost reason C doesn't have function overloading is that C does not mangle function names:
Every function in C is translated to a symbol with the same name while in C++ the name gets mangled.
An example:
Take your functions:
void foo()
void foo(char c)
void foo(int a, int b)
The symbol names as mangled by the C++ code will look the following:
void foo() = _Z3foov
void foo(char c) = _Z3fooc
void foo(int a,int b) = _Z3fooii
While in C code this will translate to:
void foo() = foo
Bottom line - C++ allows name mangling, so the compiler "changes" the function names and all references to three distinct names
C does not allow name mangling at the latest standard (and I doubt this will ever change), so such a solution is just not possible.

C vs C++ function questions

I am learning C, and after starting out learning C++ as my first compiled language, I decided to "go back to basics" and learn C.
There are two questions that I have concerning the ways each language deals with functions.
Firstly, why does C "not care" about the scope that functions are defined in, whereas C++ does?
For example,
int main()
{
donothing();
return 0;
}
void donothing() { }
the above will not compile in a C++ compiler, whereas it will compile in a C compiler. Why is this? Isn't C++ mostly just an extension on C, and should be mostly "backward compatible"?
Secondly, the book that I found (Link to pdf) does not seem to state a return type for the main function. I check around and found other books and websites and these also commonly do not specify return types for the main function. If I try to compile a program that does not specify a return type for main, it compiles fine (although with some warnings) in a C compiler, but it doesn't compile in a C++ compiler. Again, why is that? Is it better style to always specify the return type as an integer rather than leaving it out?
Thanks for any help, and just as a side note, if anyone can suggest a better book that I should buy that would be great!
Firstly, why does C "not care" about the scope that functions are defined in, whereas C++ does?
Actually, C does care. It’s just that C89 allows implicitly declared functions and infers its return type as int and its parameters from usage. C99 no longer allows this.
So in your example it’s as if you had declared a prototype as
int dosomething();
The same goes for implicit return types: missing return types are inferred as int in C89 but not C99. Compiling your code with gcc -std=c99 -pedantic-errors yields something similar to the following:
main.c: In function 'main':
main.c:2:5: error: implicit declaration of function 'donothing' [-Wimplicit-function-declaration]
main.c: At top level:
main.c:5:6: error: conflicting types for 'donothing'
main.c:2:5: note: previous implicit declaration of 'donothing' was her
For the record, here’s the code I’ve used:
int main() {
donothing();
return 0;
}
void donothing() { }
It's because C++ supports optional parameters. When C++ sees donothing(); it can't tell if donothing is:
void donothing(void);
or
void donothing(int j = 0);
It has to pass different parameters in these two cases. It's also because C++ is more strongly typed than C.
int main() {
donothing();
return 0;
}
void donothing() { }
Nice minimum working example.
With gcc 4.2.1, the above code gets a warning regarding the conflicting types for void donothing() with default compiler settings. That's what the C89 standard says to do with this kind of problem. With clang, the above code fails on void donothing(). The C99 standard is a bit stricter.
It's a good idea to compile your C++ code with warnings enabled and set to a high threshold. This becomes even more important in C. Compile with warnings enabled and treat implicit function declarations as an error.
Another difference between C and C++: In C++ there is no difference between the declarations void donothing(void); and void donothing(); There is a huge difference between these two in C. The first is a function that takes no parameters. The latter is a function with an unspecified calling sequence.
Never use donothing() to specify a function that takes no arguments. The compiler has no choice but to accept donothing(1,2,3) with this form. It knows to reject donothing(1,2,3) when the function is declared as void donothing(void).
he above will not compile in a C++ compiler, whereas it will compile in a C compiler. Why is this?
Because C++ requires a declaration (or definition) of the function to be in scope at the point of the call.
Isn't C++ mostly just an extension on C
Not exactly. It was originally based on a set of C extensions, and it refers to the C standard (with a few modifications) for the definitions of the contents of standard headers from C. The C++ "language itself" is similar to C but is not an extension of it.
and should be mostly "backward compatible"?
Emphasis on "mostly". Most C features are available in C++, and a lot of the ones removed were to make C++ a more strictly typed language than C. But there's no particular expectation that C code will compile as C++. Even when it does, it doesn't always have the same meaning.
I check around and found other books and websites and these also commonly do not specify return types for the main function
The C and C++ standards have always said that main returns int.
In C89, if you omit the return type of a function it is assumed to be int. C++ and C99 both lack this implicit int return type, but a lot of C tutorial books and tutorials (and compilers and code) still use the C89 standard.
C has some allowances for implementations to accept other return types, but not for portable programs to demand them. Both languages have a concept of a "freestanding implementation", which can define program entry and exit any way it likes -- again, because this is specific to an implementation it's not suitable for general teaching of C.
IMO, even if you're going to use a C89 compiler it's worth writing your code to also be valid C99 (especially if you have a C99 compiler available to check it). The features removed in C99 were considered harmful in some way. It's not worth even trying to write code that's both C and C++, except in header files intended for inter-operation between the languages.
I decided to "go back to basics" and learn C.
You shouldn't think of C as a prerequisite or "basic form" of C++, because it isn't. It is a simpler language, though, with fewer features for higher-level programming. This is often cited as an advantage of C by users of C. And an advantage of C++ by users of C++. Sometimes those users are the same people using the languages for different purposes.
Typical coding style in C is different from typical coding style in C++, and so you might well learn certain basics more readily in C than in C++. It is possible to learn low-level programming using C++, and the code you write when you do so may or may not end up looking a lot like C code.
So, what you learn while learning C may or may not inform the way you write C++. If it does, that may or may not be for the better.
C++ has changed these rules on purpose, to make C++ a more typesafe language.
C.1.4 Clause 5: expressions [diff.expr]
5.2.2
Change: Implicit declaration of functions is not allowed
Rationale: The type-safe nature of C++.
Effect on original feature: Deletion of semantically well-defined feature. Note: the original feature was
labeled as “obsolescent” in ISO C.
Difficulty of converting: Syntactic transformation. Facilities for producing explicit function declarations
are fairly widespread commercially.
How widely used: Common.
You can find other similar changes in appendix C of this Draft C++ standard
Isn't C++ mostly just an extension on C
No. If you think of C++ as "C with Classes", you're doing it very, very wrong. Whilst strictly, most valid C is valid C++, there's virtually no good C that's good C++. The reality is that good C++ code is vastly different to what you'd see as good C code.
Firstly, why does C "not care" about the scope that functions are
defined in, whereas C++ does?
Essentially, because not enforcing the same rules as C++ makes doing this in C hideously unsafe and in fact, nobody sane should ever do that. C99 tightened this up, along with implicit-int and other defects in the C language.

Could C++ or C99 theoretically be compiled to equally-portable C90?

This is a big question, so let me get a few things out of the way:
Let's ignore the fact that some C++ features cannot be implemented in C (for example, supporting pre-main initialization for any global static object that is linked in).
This is a thought experiment about what is theoretically possible. Please do not write to say how hard this would be (I know), or that I should do X instead. It's not a practical question, it's a fun theoretical one. :)
The question is: is it theoretically possible to compile C++ or C99 to C89 that is as portable as the original source code?
Cfront and Comeau C/C++ do compile C++ to C already. But for Comeau the C they produce is not portable, according to Comeau's sales staff. I have not used the Comeau compiler myself, but I speculate that the reasons for this are:
Macros such as INT_MAX, offsetof(), etc. have already been expanded, and their expansion is platform-specific.
Conditional compilation such as #ifdef has already been resolved.
My question is whether these problems could possibly be surmounted in a robust way. In other words, could a perfect C++ to C compiler be written (modulo the unsupportable C++ features)?
The trick is that you have to expand macros enough to do a robust parse, but then fold them back into their unexpanded forms (so they are again portable and platform-independent). But are there cases where this is fundamentally impossible?
It would be very difficult for anyone to categorically say "yes, this is possible" but I'm very interested in seeing any specific counterexamples: code snippets that could not be compiled in this way for some deep reason. I'm interested in both C++ and C99 counterexamples.
I'll start out with a rough example just to give a flavor of what I think a counterexample might look like.
#ifdef __SSE__
#define OP <
#else
#define OP >
#endif
class Foo {
public:
bool operator <(const Foo& other) { return true; }
bool operator >(const Foo& other) { return false; }
};
bool f() { return Foo() OP Foo(); }
This is tricky because the value of OP and therefore the method call that is generated here is platform-specific. But it seems like it would be possible for the compiler to recognize that the statement's parse tree is dependent on a macro's value, and expand the possibilities of the macro into something like:
bool f() {
#if __SSE__
return Foo_operator_lessthan(...);
#else
return Foo_operator_greaterthan(...);
#endif
}
It is not only theoretically possible, but also practically trivial - use LLVM with a cbe target.
Theoretically all Turing-complete languages are equivalent.
You can compile C++ to an object code, and then decompile it to plain C or use an interpreter written in plain C.
In theory of course anything could be compiled to C first, but it is not practical to do so, specifically for C++.
For Foo operator< in your example it could be converted to:
bool isLess(const struct Foo * left, const struct Foo * right );
as a function signature. (If C90 doesn't allow bool then return int or char, and similarly old C versions that don't allow const, just don't use it).
Virtual functions are more tricky, you need function pointers.
struct A
{
virtual int method( const std::string & str );
};
struct A
{
int (*method)( struct A*, const struct string *);
};
a.method( "Hello" );
a.method( &a, create_String( "hello" ) );
// and take care of the pointer returned by create_String
There are a number of subtle differences. For example, consider the line:
int i = UINT_MAX;
IIRC, in C++ this assigns an implementation-defined value. In C99 and C89, it assigns an implementation-defined value, or raises an implementation-defined signal. So if you see this line in C++, you can't just pass it through to a C89 compiler unmodified unless you make the non-portable assumption that it won't raise a signal.
Btw, if I've remembered wrong, think of your own example of differences in the standards relating to relatively simple expressions...
So, as "grep" says, you can do it because C89 is a rich enough language to express general computation. On the same grounds, you could write a C++ compiler that emits Perl source.
By the sound of your question, though, you're imagining that the compiler would make a set of defined modifications to the original code to make it compile as C89. In fact, even for simple expressions in C++ or C99, the C89 emitted might not look very much like the original source at all.
Also, I've ignored that there may be some parts of the standard libraries you just can't implement, because C89 doesn't offer the capabilities, so you'd end up with a "compiler" but not a complete implementation. I'm not sure. And as dribeas points out, low-level functions like VLAs present problems - basically you can't portably use the C89 "stack" as your C99 "stack". Instead you'd have to dynamically allocate memory from C89 to use for automatic variables required in the C99 source.
One big problem is exceptions. It might be possible to emulate them using setjmp, longjmp etc., but this would always be extremely inefficient compared to a real device-aware unwind engine.
http://www.comeaucomputing.com
There's no better proof of feasibility than a working example. Comeau is one of the most conforming c++03 compiler, and has support for many features of the upcoming standard, but it does not really generate binary code. It just translates your c++ code into c code that can be compiled with different C backends.
As for portability, I would assume it is not possible. There are some features that cannot be implemented without compiler specific extensions. The first example that comes to mind is C99 dynamic arrays: int n; int array[n]; that cannot be implemented in pure C89 (AFAIK) but can be implemented on top of extensions like alloca.