This question already has answers here:
Why do the older C language specs require function-local variables to be declared up-front?
(3 answers)
Closed 7 years ago.
I have been going through a bit of history of C, and I find that in earlier versions of C, like in C89 standard, it is mandatory to declare variables at the beginning of a block.
But I also find there are some relaxations from C99 standard specification, where variable can be declared anywhere before it is used.
My question is why the earlier versions made it mandatory? my emphasis is to know if there was any technical difficulties in designing the compiler at those days, that prevented them identifying declarations at any point.
Also, with a compiler design perspective I understand, with such a restriction in C89, it is easy to handle variable declarations and usage with the help of an intermediate file to store the mappings. But are there methods that can handle the case without using an intermediary file, say some memory based storage?.
If the compiler sees a consolidated list of all the local/automatic variables up front, it can immediately work out the total amount by which to move the stack pointer to reserve stack memory for them - just one operation on the stack pointer. If it handles the variables in dribs and drabs as they're encountered in the function, moving the stack pointer incrementally, then there ends up being more opcodes dedicated to stack setup and stack pointer updates. It's important that the stack pointer be up to date whenever a further function call's performed. Newer compilers do a tiny bit of extra work to patch back in the amount by which to move the stack pointer after all the function's been considered. (I'd hazard that the effort's so minimal that the early Standard was shaped more by the conceptual appeal of knowing what to do up front than the effort of being more flexible, but if you just want to get something working - why make extra efforts?)
C99 Rationale didn't directly explain why it was not permited in C89, but did say it was added in C99 because it was permited in other languages and the it has been found useful.
Rationale for International Standard — Programming Languages — C
§6.2.4 Storage durations of objects
A new feature of C99: C89 requires all declarations in a block to occur before any statements. On the other hand, many languages similar to C (such as Algol 68 and C++) permit declarations and statements to be mixed in an arbitrary manner. This feature has been found to be useful and has been added to C99.
I am a newbie to Fortran. Please look at the code below:
c main program
call foo(2)
print*, 2
stop
end
subroutine foo(x)
x = x + 1
return
end
In some implementations of Fortran IV, the above code would print a 3. Why is that? Can you suggest an explanation?
How do you suppose more recent Fortran implementations get around the problem?
Help is very much appreciated. Thank You.
The program breaks the language rules - the dummy argument x in the subroutine is modified via the line x = x + 1, but it is associated with something that is an expression (a simple constant). In general, values that result from expressions cannot be modified.
That specific code is still syntactically valid Fortran 2008. It remains a programming error in Fortran 2008 - as it was in Fortran IV/66. This isn't something that compilers are required to diagnose. Some may, perhaps with additional debugging options, and perhaps not till runtime.
Because the program breaks the language rules anything could happen when you run the program. Exactly what depends on the code generated by the compiler. Compilers may have set aside modifiable storage for the value that results from the expression such that it internally looks like a variable (the program might print three and the program carries on), that modifiable storage might be shared across the program for other instances of the constant 2 (suddenly the value of 2 becomes three everywhere!), the storage for the value of the constant might in non-modifiable memory (the program may crash), the compiler may issue an error message, the program may get upset and sulk in its bedroom, the program might declare war on a neighbouring nation - it is a programming error - what happens is unspecified.
As of Fortran 90, facilities were introduced into the language to allow programmers to write new code that is practical for compilers to check for errors such as these (and in some cases compilers are required to check for errors if they are to be regarded as standard conforming).
For the code as presented, the main program and the subroutine are to be regarded as separately compiled - the main program is unaware of the details of the subroutine and vice versa (it is possible that the subroutine could be compiled long after the main program, on a different machine, with the outputs of the two being linked together at some later stage - without fancy link time behaviour or static analysis it is therefore not possible to resolve errors such as this). Language rules are such that when compiling the main program the compiler must implicitly assume the details of the interface of the subroutine based only on the way the subroutine is referenced - inside the main program the subroutine has an implicit interface.
Fortran 90 introduced the concept of an explicit interface, where the compiler is explicitly told what the interface of the subroutine in various ways, and can then check that any reference to the subroutine is consistent with that interface. If a procedure is a module procedure, internal procedure or intrinsic procedure - that interface is automatically realized, alternatively for external subprograms, procedure pointers, etc, the programmer can explicitly describe the interface using an interface block.
In addition, Fortran 90 introduced the intent attribute - a characteristic of a dummy argument of a procedure that is also then a characteristic of the interface for a procedure. The intent of the argument indicates to the compiler whether the procedure may define the argument (it also may implications for default initialization and component allocation status) and hence whether an expression could be a valid actual argument. x in subroutine foo would typically be declared INTENT(INOUT).
Collectively these new language features provide a robust defence against this sort of programming error when using compilers with a basic level of implementation quality. If you are starting with the language then it is recommended that these new features become part of your standard approach - i.e. use implicit none, all procedures should generally be module procedures or internal procedures, use external procedures only when absolutely required, always specify dummy argument intent, use free form source.
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