| Jul | AUG | Sep |
| 08 | ||
| 2012 | 2013 | 2014 |
COLLECTED BY
Collection: Wide Crawl started August 2013
Cee Language
int main()
{
void (*i_am_bleeding)() = (void(*)())15;
i_am_bleeding();
return 0;
}
The problem with C is the techniques that help it compete with modern dynamic languages are invariably the techniques that make it dangerous.
The C language was created by DennisRitchie over the period 1969 through 1973, based on predecessor languages B and BCPL. By '73 it could reimplement Unix on an early PDP 11. Unix had been implemented purely in assembly before that. See KernighanAndRitchie (book).
It was one of the first successful high-level systems programming languages, and since the 1980s has been the most widely used systems programming languages, mostly displacing assembly code for that purpose. See also BlissLanguage.
A very insightful contrarian comment about the nature of C appears in an AlexanderStepanov (C++ STL designer) interview by Al Stevens in DrDobbsJournal (3/1995) (http://www.sgi.com/tech/stl/drdobbs-interview.html):
"Let's consider now why C is a great language. It is commonly believed that C is a hack which was successful because Unix was written in it. I disagree. Over a long period of time computer architectures evolved, not because of some clever people figuring how to evolve architectures---as a matter of fact, clever people were pushing tagged architectures during that period of time---but because of the demands of different programmers to solve real problems. Computers that were able to deal just with numbers evolved into computers with byte-addressable memory, flat address spaces, and pointers. This was a natural evolution reflecting the growing set of problems that people were solving. C, reflecting the genius of Dennis Ritchie, provided a minimal model of the computer that had evolved over 30 years. C was not a quick hack. As computers evolved to handle all kinds of problems, C, being the minimal model of such a computer, became a very powerful language to solve all kinds of problems in different domains very effectively. This is the secret of C's portability: it is the best representation of an abstract computer that we have. Of course, the abstraction is done over the set of real computers, not some imaginary computational devices. Moreover, people could understand the machine model behind C. It is much easier for an average engineer to understand the machine model behind C than the machine model behind Ada or even Scheme. C succeeded because it was doing the right thing, not because of AT&T promoting it or Unix being written with it." (emphasis added)
C became successful because it provided a range of data and control structures that were general enough to be sufficient for many programming tasks, but limited enough to be fairly easy to implement efficiently on common computer architectures. Assembly language was in near universal use for systems programming in the 1970s; to be a suitable replacement, C needed to offer comparable speed with improved usability. To that end it offered relative machine independence, structured control constructs (if, while, for), and importantly, TextSubstitutionMacros, which are widely deplored today but which were wildly popular in AssemblyLanguages.
C supports
● characters, integers, floating point numbers, pointers, and multi-dimensional arrays.
● user-definable records ("structures") including bit-fields
● Infix operators for arithmetic, comparisons, bitwise and/or/xor/not/shift, logical short-circuited and/or/not, ternary ConditionalOperator
● Basic StructuredProgramming control constructs (if, for, while, do-while, SwitchStatement, goto)
● Simple return-stack functions (recursive but not first class, not nested, no LexicalClosures, indeed no lexical scoping beyond "global scope", "file scope", "block scope" at all)
● FunctionPointers are (almost) first-class entities in C; you cannot create new functions at runtime but a FunctionPointer, once bound to a function, can be used like any other object.
● AssignmentsAreExpressions
● Automatic management of stack-allocated variables local to functions
●ACeeStandardLibrary of functions for strings, floating point, OS interface, and an innovative portable I/O library (At least, innovative for 1970. By modern standards, stdio is quite limited; the existence of other de-facto standard I/O libraries like that defined in POSIX.1 remedies the situation quite a bit.)
● Very little else
A note on the CeePreprocessor copied from TrivialDoWhileLoop:
For years it wasn't considered part of the C language per se, and was advocated, designed, and implemented by different people than the rest of C: Alan Snyder, Mike Lesk, and John Reiser. See Ritchie's history of C at http://cm.bell-labs.com/cm/cs/who/dmr/chist.html.
The design of the preprocessor is horrid in several ways, but on the other hand, Reiser's implementation of it is an amazing case study in how to make software run really, really, really fast. In one environment I used in the 1980s, it was faster than "cat file.c > /tmp/foo"! ("cat" uses getchar() and the stdio lib was inefficient).
Although often criticized for being a "low-level HighLevelLanguage", this is also C's strength, allowing very fast MachineCode to be generated for an especially wide range of types of programs, making it especially suitable for a systems programming language.
A variety of more sophisticated languages have been claimed to be suitable as replacements for C, but as of 2003 there still are no other candidates that are 100% technically successful in matching or surpassing C in its areas of strengths.
On the other hand, C has been displaced to a noticeable extent in non-systems programming areas, and displaced to a certain (and some say growing) extent even in systems programming, by languages such as C++, Java, Perl, etc.
The lack of Object Oriented features in C creates dissatisfaction, but nonetheless CeePlusPlus is not universally considered to be a suitable replacement for C due to a large variety of perceived flaws, including complexity.
void strcpy(char *from, char *to) {
while(*to++ = *from++);
}
Is this intentionally wrong?
What's wrong with it? Is it the fact that the designers care deeply that it should run fast and care little that *from might not be terminated and overrun memory? Is that a problem? That's a user problem... I'd call it a LanguageUsability problem.
Well, actually one thing wrong with it is that the CeeStandardLibrary strcpy has the destination argument first...
And the other thing wrong is that the standard library defines strcpy to return a char * to the destination string. Besides, from is a const pointer, as we don't modify the source string.
from the man page:
#include <string.h> char *strcpy(char *dest, const char *src);So I'd say a better try to this particular part of the library would be:
char *strcpy(char *to, const char *from) {
char * tmp = to;
while ( *to++ = *from++ )
// look ma, nothing in here, C99 comment style :-)
;
return tmp;
}
Except that the arguments are restricted pointers according to the C99 Standard, so even the above isn't quite right. -- JamesDennett
Heretics. The reason strcpy is a library call is to have it optimised for each architecture. The infamous empty-block while() above is 5-30 times slower than dedicated assembly, depending on the architecture.
BTW, it'd be better using char *strncpy(char *to, const char *from, size_t num), no buffer overflows.
''Not necessarily, strncpy doesn't guarantee NUL-termination, so you still have to check the result. Better to explicitly
check, or use a real string library. Don't even think about strncat().''
No you don't.
strncpy(dst, src, n); dst[n-1] = 0;End of discussion, and no "checking" necessary. If src is too big to fit in dst, then it would have been truncated anyway. This is something you'd have to check for with strcpy anyway to prevent a buffer overflow.
char* this_variable_will_store_a_string
Now... my understanding of these things is that char* tells you we're dealing with a pointer to a variable of type character but
● how big is this variable? (the one being pointed to)
● Anyone's guess.
● How long can the string be?
● As long as the allocated memory permits (note the need for null termination).
● How is the memory allocated?
● ItDepends. It could be that the char * is intended to point into a previously declared char[], or it might be intended to point at malloc()ed memory; and the malloc might occur pretty much anywhere.
Thanks for answering me so quickly! Here's another question:
● If you try to store a string that is too long in some memory that is not big enough, can you accidently overwrite memory which contains other (possibly very important) data?
● Yes. It often happens. C programmers are notoriously lazy about checking for the maximum length of data put into a buffer. The language provides no automatic checking. This type of programming error is often used by crackers to deliberately overwrite data in memory in order to modify values or even take control of the program. See CeeLanguageAndBufferOverflows
EditText of this page
(last edited June 28, 2013)
or FindPage with title or text search