C is a programming language, most notable as the implementation language of Tcl ;)
The ANSI committee as well as the ISO committee have approved a standard reference for C.
Support for C is traditionally provided by a compiler. Some efforst at a C interpreter also exist.
Most Unix systems provide vendor-supported compilers. They are often unbundled products these days.
Support for C can also take the form of a run-time compiler.
tcc provides a libtcc library, which allows a running program to compile and link C code without touching disk. In milliseconds for a small chunk of code. (x86 only as of Jun 2003)
AMG: One annoying thing about C is that, like Fortran, it uses = as its assignment operator. This is very easy to confuse with the comparison operator ==, resulting in either of the following two coding errors:
x == 5; /* Nothing happens, except maybe a warning if -Wall is on. */ if (x = 6) {...} /* Unintended assignment and incorrect logic. */
Algol uses := as its assignment operator, and C is ancestrally derived from Algol, so I was always mystified about why C reverted to Fortran's assignment syntax. But I just now figured it out, I think. A := assignment operator looks almost identical to C's != inequality operator, so using := instead of = for assignment simply trades one potential coding error for another. To fix that problem, != would have to be replaced with, say, /= (borrowed from Ada), but that (1) collides with the compound division and assignment operator /= and (2) breaks symmetry with the logical negation operator !. Or instead use \=, but that will behave unexpectedly when placed inside double quotes. Or use <> and be like BASIC and SQL. Shrug!
PL: the change from := to = was made during the transition from BCPL to B (and simply kept when going from B to C), and IIRC the reason was that Ken Thompson felt that an operator that was going to be used as often as assignment was should be as short as possible. The reasons you mention may of course also have affected his decision, but there was never any secondary ambiguity with "divide-assign", which was written as =/ in B.
bch: One thing that I do in C (indeed, Perl too) is use typical rvalues on the left side when doing comparisons, which will fail compilation if the assignment operator is mistakenly used instead of the comparison operator. Eg: use if(9==a){...} instead of if(a==9){...}; in the case of mistakenly using assignment operator, this will fail if(9=a){...}, which is good; the programmer will be notified that his intent was mis-typed. If the rvalue is indeed on the right, though, one would have typed if(a=9){...}, which will compile, but is unlikely to represent the programmer's intent, and lead to hard-to-find bugs. Reading expressions written this way (w/ rvalues on left) may seem "backward" to some people, and the practice is affectionately dubbed Yoda Conditions , [L4 ]
AMG: Cute. I've seen that style too. Unfortunately, it doesn't help when both sides of the comparison (or unintended assignment) are valid lvalues. Thankfully, gcc -Wall provides useful warnings:
x == y; | warning: statement with no effect |
if (x = y) {...} | warning: suggest parentheses around assignment used as truth value |
To silence the latter warning on a case-by-case basis, type: if ((x = y)) {...}. In my opinion, the extra parentheses highlight the fact that this expression isn't Business As Usual, so the reader will look at it more carefully and is more likely to notice that it uses assignment instead of comparison. Of course, only silence this warning when the code really is doing what you intend, and please put a comment nearby to testify to this fact and explain why. Also, watch your warnings like a hawk, and don't release code that emits any warnings in your chosen build environment(s). (You can't control if some alien compiler puts out weird warnings because it used MS-Word to grammar-check your comments.)
Sometimes I really do want my conditional expression to have the side effect of assigning into a variable. I need this when I want to save some intermediate value of a complex conditional for later processing. A simple example is calling a syscall (read()) that either returns a useful result (number of bytes read) or an error flag (-1, check errno for details).
if ((ret = read(fd, buf, max)) == -1) { perror("read"); } else { printf("read %d bytes\n", ret); }
This style is also available in Tcl:
proc getline {} {...} while {[set line [getline]] ne ""} { puts "got header line: $line" } puts "got blank line, the header is now done"
As you can see, Tcl makes it impossible to mix up assignment and comparison. ;^)
PYK 2015-07-30: Undefined behaviour, in combination with optimizing compilers, leads to unpleasant surprises. Here is one from the Linux kernel, as described by A Guide to Undefined Behaviour in C and C++, Part1 , John Regehr, 2015-07-21:
static void __devexit agnx_pci_remove (struct pci_dev *pdev) { struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct agnx_priv *priv = dev->priv; if (!dev) return; ... do stuff using dev ... }
The error is that since the behaviour of dev->priv is undefined if dev is NULL, a compiler might decide to omit the following check for null, leading the program to do stuff using dev when dev is null, and even though there is an explicit check in the code for the case that dev is null. Apparently this is exactly what some versions of gcc do.
How does performance in Tcl compare to comperable programs in C?
For instance, certainly there are types of programs which can likely be developed more quickly in Tcl than in C.
Are there types of things that run faster in Tcl than C? If not, how much slower than C is Tcl? 10 times slower? 50 times slower? 100 times slower?
AMG: I just thought of a cute alternate name for C: "lightspeed". You know, 'cuz physicists use the constant "c" to represent the speed of light. :^) I leave it up to you to figure out if this name has any deeper meaning. At least it would give C an excuse to have a snazzy, energetic theme song .