FREE | LITE: $20.00 | FULL: $80.00 |
---|---|---|
50 source lines | 5000 source lines | Unlimited |
1 Source File | Unlimited | Unlimited |
1 Header File | Unlimited | Unlimited |
Parse C Declarations | ||
Object Browser | ||
Download | Buy Now | Buy Now |
Tenacious C The Visual C IDE and Graphical Editor
Tenacious C depicts your C programs graphically.
With our easy-to-use display, you can
- Ensure pointers are initialized
- Quickly identify memory leaks
- Investigate program data
- See what points to what
- See how close you are to an overflow using the stack meter
- Enable a variety of memory views, allowing you to investigate virtually all program data
- Cast memory from one type to another
Learn C using a memory view
As you learn C, you'll understand how your computer sees your program.
Your pointers, memory, and variables will be depicted automatically.
The memory view will update as your program runs.
Debug Smarter
Uninitialized Pointers
Warning icons are displayed when pointers don't display to valid memory
Memory Leaks
Inaccessible memory is marked with a red border for easy detection
Stack Overflow
Our stack meter lets you know how close your program is to annihilation
Teaching C, Learning C
Corporate
- Reduce training costs.
- Workshop existing code bases.
- Facilitate senior-junior mentoring.
Academic
- Ideal for group learning.
- Classroom discounts available.
Memory Explorer
Trace pointers
The object view displays all memory information from the compiled program including stack, dynamic, and global memory in a visually intuitive manner.
Show leaked memory
All memory representations such as structures or arrays are depicted in the object view. You can choose to interact with the object view by using the mouse to manipulate the position of certain parts of memory, click on pointers for source and target information, show specific regions of arrays, and many other functions.
Monitor stack activity
You can monitor the global, stack, and dynamic memory separately along with individual functions on the call stack.
Guided Debugger
Tenacious C provides powerful text-navigating features to help reduce code time and enhance debugging capabilities. For example, the 'Find all References' feature allows the user to find all references of a certain member or function used in the project. This includes any source or header file that comprises the current project.
Show leaked memory
All memory representations such as structures or arrays are depicted in the object view. You can choose to interact with the object view by using the mouse to manipulate the position of certain parts of memory, click on pointers for source and target information, show specific regions of arrays, and many other functions.
Monitor stack activity
You can monitor the global, stack, and dynamic memory separately along with individual functions on the call stack.
Double-clicking on any of the valid search results will take you to the location of the selected result.
Pointer Visualizations
Pointers are sometimes difficult to conceptualize for programmers both new and old. The Object View simplifies pointer usage by using arrows to make the logical connections of what pointers are actually pointing to in memory. The Object View will also show uninitialized pointers denoted by red exclamation points next to the pointer variable names. This alerts the user right away that the uninitialized pointer will most likely fail to work properly and can give very unpredictable results. These indicators are part of the program's symbolic identifier buttons.
For Teachers
Teaching C to beginners can be problematic due to the fact that C requires familiarity with the machine architecture in order to program with it effectively. Even programmers experienced with other, higher-level languages can hit a roadblock when faced with concepts like pointers, memory, arrays, and the stack. Tenacious C enables rapid understanding of the C programming language by depicting these concepts visually, in real-time.
Show visual cues with the Memory Explorer
When your students can read memory allocations during development from an easy to read graphical visual explorer they will not only learn how to program more quickly, but they'll not run into runtime memory errors. This will help encourage good programming habits and cleaner code.
Latest News
test news story
test
Articles
Forums Are Operational
The forums are live again. Hopefully the new forum software (XenForo) will help with the spam problems we’ve had in the past. It certainly feels smoother than vBulletin. Over the next couple weeks we’ll be starting threads on various support issues. There are also subforums for C programming and general tech topics.
Tenacious C 1.25 Released
Version 1.25 of Tenacious C was released today.
New features include:
- Folder Import Wizard
This feature constructs a Tenacious C project from the .h and .c files in a folder. Useful for pulling in existing projects without having to add every file manually.
- Scriptable Deployment
Intended for university and corporate customers, this command-line feature installs and registers Tenacious C across multiple machines. No manual intervention is needed to complete the deployment. Useful for scenarios in which the machines in a computer lab are wiped and then repopulated on a semi-regular basis.
C, The Beautiful Language
They call soccer the beautiful game, and when we watch Ronaldo doing things on the pitch that no earthly being should be allowed to, we understand why.
And yet, to me, it’s not so much the ungodly talent of the superstars that makes the sport such a pleasure to watch, but more the beating heart of the match itself. The slow, ordinary rhythms that come between the highlight plays. The tidal, life-like forces that propel a team toward its goal and the equally strong counter-forces that prevail from the opposite direction.
Watching a good match, I get the sense that the gameplay exists unto itself — that the players are merely agents to it. Soccer is a simple sport. One ball, forty-four feet, two goals, and grass. There’s nothing preventing the living soul of the game from speaking to us directly. We see this and feel this, and we (or at least I) say soccer is the beautiful sport.
When I look at good C code, I feel the same way.
On slow days, I’ll poke around the kernel, sched.c, page_alloc.c, etc., and it very much feels like I’m peering in on a living thing. I can see the code steering the execution, the logic funneling the energy of the program, and even though I’m not a kernel hacker, I can almost get the gist of what I’m looking at simply by watching the way the code “moves”.
In other languages, the abstractions and sweet (if helpful) syntactic sugar that attend the code conceal the heartbeat. But in C, as in soccer, the quickening happens on the ground. A simple syntax, a smattering of keywords, an almost perfect description of a general Von Neumann machine. In C, the spirit of the program speaks to us directly. We see this and feel this, and we say —
C, the beautiful language.
How Duff’s Device Works
I like C, but I have to admit that, sometimes, “The Old Man of Programming” can be a bit of a killjoy. This is one of the most exciting eras in computer history, but lately, C’s acting like he doesn’t even want to have a good time. While the cool kids like Ruby and Haskell are living it up, C’s over in the corner obsessing over bits and bytes and memory alignment and pointers and the stack and machine architecture and unreachable allocations and multiple indirections…and it’s…kind of a buzzkill. You want to tell him, “Dude! Lighten up! This is supposed to be fun!”
But of course C can’t relax. He’s holding the entire computing universe on his shoulders, after all. It’s not turtles all the way down — it’s turtles all the way down, then C. Not a lot of room for fun underneath that, is there?
Is there?
Well. Here’s the secret: C does let loose sometimes. And after being bottled up for so long, when the release finally does come, it’s pretty much an F5 of crazy.
Take for example a little thing called Duff’s Device:
send(short *to, short *from, int count) { int n=(count+7)/8; switch(count%8){ case 0: do{ *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; }while( --n>0); } }
Okay, what you have here is your basic switch statement merged with a do loop. Pretty messed up, right? And just to be clear: this is totally valid C.
Huh?
If we look at the Jargon File entry, we see that the purpose of Duff’s Device is to continuously copy data into a memory-mapped video register. Unfortunately, there’s no explanation of how it works, other than a brief mention of C’s default fall-through property. Call me crazy, but fall-through is about the only part of Duff’s Device that actually makes sense. What about the fact that there’s a friggin do loop embedded in a switch statement? Or the fact that case labels are, in turn, embedded inside the do? This thing is so caught up in itself it makes a teenager seem reflective.
However, since I started working on Tenacious C, I’ve gotten real intimate with the C grammar, and with C in general, and I can report to you that Duff’s Device isn’t as horrific as it appears. In fact, the reason it’s so shocking is because most people don’t really understand switch statements in C.
Switch Statements In General
If you’re like me, you’ve always visualized a switch as a glorified if-then-else block.
It makes sense to say that…
switch(x) { case 1: printf("something1\n"); break; case 2: printf("something2\n"); case 3: printf("something3\n"); break; case 4: printf("something4\n"); break; }
…is pretty much equivalent to:
if(x == 1) printf("something1\n"); else if(x == 2 || x == 3) { if(x == 2) printf("something2\n"); printf("something3\n"); } else if(x == 4) printf("something4\n");
Right? You can see with your own eyes that the two statements produce the same result. I even omitted a break to ensure that our old friend Mr. Fall-Through didn’t break (har, har) the model. For workaday programming, this is a perfectly valid way of thinking about a switch.
But it breaks down in Duff’s Device.
If you’re in the “switch as if-then-else” frame of mind when you see Duff’s Device, your brain will try to overlay a do loop over an if-then-else block. But your brain will resist, because what it’s trying to do is impossible…and that’s where a lot of the confusion over Duff’s Device arises from.
Switch Statements In C
Here’s how a switch really works.
You type this…
switch(x) { case 1: printf("something1\n"); break; case 2: printf("something2\n"); case 3: printf("something3\n"); break; case 4: printf("something4\n"); break; }
…and C sees this:
if(x==1) goto label_case1; if(x==2) goto label_case2; if(x==3) goto label_case3; if(x==4) goto label_case4; goto label_finish; label_case1: printf("something1\n"); goto label_finish; label_case2: printf("something2\n"); label_case3: printf("something3\n"); goto label_finish; label_case4: printf("something4\n"); goto label_finish; label_finish: /* continue with the rest of the program */
See how that works? To C, a switch is really a bank of cascading gotos. That’s why case labels have to be constant, because C generates goto labels from them at compile time. And unlike an if-then-else block, goto labels can easily be intertwined with a do loop. In fact, let’s go ahead and rewrite Duff’s Device using this model:
send(short *to, short *from, int count) { int n=(count+7)/8; if(count%8 == 0) goto label_case0; if(count%8 == 1) goto label_case1; if(count%8 == 2) goto label_case2; if(count%8 == 3) goto label_case3; if(count%8 == 4) goto label_case4; if(count%8 == 5) goto label_case5; if(count%8 == 6) goto label_case6; if(count%8 == 7) goto label_case7; label_case0: do{ *to = *from++; label_case7: *to = *from++; label_case6: *to = *from++; label_case5: *to = *from++; label_case4: *to = *from++; label_case3: *to = *from++; label_case2: *to = *from++; label_case1: *to = *from++; }while( --n>0); }
Sweet! The switch is gone, the control flows in a way that makes sense, and the do loop runs without any problems. So…case closed, right?
Almost.
C — An Old Man, But A Liberal At Heart
You remember at the top, I had two questions about Duff’s Device:
-
1. How do you embed a do loop inside a switch statement?
2. How are case labels, in turn, embedded inside the do?
Well, we just answered question two. (They’re not case labels per se, but goto labels.)
Question one is trickier. Question one depends on familiarity with a certain quirk of the C language. As far as I know, no other high level language in existence, with the exception of C++, gives you the freedom C does to cram whatever the hell you want inside a switch. The only demand C makes is that the switch statement be followed by a statement. What’s a statement? Let’s look at the grammar:
statement : labeled_statement | compound_statement | expression_statement | selection_statement | iteration_statement | jump_statement ;
So you can have a labeled statement (a single case or goto label), a compound statement (any number of statements enclosed by braces. This is by far the most common), an expression statement (any random expression, for instance an assignment), a selection statement (an if statement), an iteration statement (for, while, do), or a jump statement (goto, break, continue, return).
Duff’s device employs a do loop inside a switch.
switch(x) /* notice that enclosing braces aren't necessary */ do{ .... }while(x > 100);
But just for fun we can try a for loop…
int y; switch(x) /* notice that enclosing braces aren't necessary */ for(y=x; y<10; y++{ .... }
...or an if statement.
int a; int b; switch(x) /* notice that enclosing braces aren't necessary */ if(a == b) { .... }
Try compiling those examples. You'll see they work. (Obviously, you'll have to replace the ellipses with real code.) Now, is this something you'll ever use in practice? Well, Tom Duff found a use for it. So who knows? But I'm leaning toward...nah.
Conclusion
So there you have it. Duff's Device is a truly bizarre programming construct, made possible by C's leniency when it comes to switch statements, and by the cascading-goto nature of the switch itself. Any questions, feel free to ask in the comments.
Hat tip: thanks to Mike Gleen for catching a small bug in the example code.