Slashdot Mirror


Best Practices for Programming in C

An anonymous reader writes "Although the C language has been around for close to 30 years, its appeal has not yet worn off. It continues to attract a large number of people who must develop new skills for writing new applications, or for porting or maintaining existing applications. This article provides a set of guidelines that can help you with your coding."

42 of 123 comments (clear)

  1. I wish C were that popular! by bluethundr · · Score: 3, Interesting

    Although the C language has been around for close to 30 years, its appeal has not yet worn off.

    I'm sure that in some ways that statement may be true, but I've been trying for MONTHS to get people interested in the C/C++ Meetups! Compared to Python you'd think we were trying to start a Sanskrit study group!

    btw..fp? hee hee!

    --
    Quod scripsi, scripsi.
  2. Looks like the author also knows VB by stef0x77 · · Score: 2, Informative

    From the article:

    for(i=0 to 100)
    array[i]=0

    Maybe I missed something but since when is that C?

    1. Re:Looks like the author also knows VB by vadim_t · · Score: 2

      That doesn't look like any language I know. If that was VB then it would have been:

      For i = 0 To 100
      array(i) = 0
      Next

      Brain fart, I suppose.

    2. Re:Looks like the author also knows VB by avalys · · Score: 5, Informative

      The article specifically refers to the snippet you mentioned as pseudocode, not C.

      --
      This space intentionally left blank.
    3. Re:Looks like the author also knows VB by jilles · · Score: 2, Funny

      they probably left out some #define's that make it valid C :-)

      --

      Jilles
  3. Write in C by pauljlucas · · Score: 4, Funny
    (Sing this as you would "Let it Be.")
    When I find my code in tons of trouble,
    Friends and colleagues come to me,
    Speaking words of wisdom:
    "Write in C."

    As the deadline fast approaches,
    And bugs are all that I can see,
    Somewhere, someone whispers:
    "Write in C."

    Write in C, Write in C,
    Write in C, oh, Write in C.
    LOGO's dead and buried,
    Write in C.

    I used to write a lot of FORTRAN,
    For science it worked flawlessly.
    Try using it for graphics!
    Write in C.

    If you've just spent nearly 30 hours,
    Debugging some assembly,
    Soon you will be glad to
    Write in C.

    Write in C, Write in C,
    Write in C, yeah, Write in C.
    BASIC's not the answer.
    Write in C.

    Write in C, Write in C
    Write in C, oh, Write in C.
    Pascal won't quite cut it.
    Write in C.

    --
    If you reply, do so only to what I explicitly wrote. If I didn't write it, don't assume or infer it.
  4. scanf replacement? by ichimunki · · Score: 2, Interesting

    (please note: I'm still learning C) So what should I be using instead of scanf? The article recommends against it, but doesn't say whether there is a better way to get some input and get interesting chunks out of it.

    --
    I do not have a signature
    1. Re:scanf replacement? by Saint+Nobody · · Score: 2

      ack! no way!

      use strtol, strtoll, strtoul, strtoull, strtof, strtod, and/or strtold. they're much better functions. all of them except strtol, strtoul and strtod are relatively recent additions, though, so you might want to stick to those 3 for now.

      --
      #define F(x) int main(){printf(#x,10,#x);}
      F(#define F(x) int main(){printf(#x,10,#x);}%cF(%s))
    2. Re:scanf replacement? by jguthrie · · Score: 2, Informative
      Functions in the scanf family are truly useful, if you can grok them. However, error recovery can be a pain, so it's not generally advisable to use scanf() or fscanf(). Instead, one practice that I use is to read lines into a buffer (using fgets so that you'll be less likely to have a buffer overflow) and then run sscanf on it.

      You should always check the return value from any functions in the scanf family against the number of items whose value you want to set. That will tell you whether or not you've read everything you expected. Also, bear in mind that it can be tricky to set up the format string properly. I can't think of any examples of nonobvious behavior off the top of my head, but I find I use a lot character sets when I use scanf.

  5. Re:Best practice? Don't use it! by sporty · · Score: 3, Insightful

    C is really just glorified assembly language. It only provides a minimal of type checking over most macro assemblers and is about as easy to read. It does have alot of operators to save typing though.


    But for embeded systems, where your resources may be very limited, wouldn't a good optimizing compiler do a better job than an OO one?

    I'm sure an assembly code monkey could do better than a c junkie, but I wouldn't know the rankings between the compiled code now-a-days as a desktop programmer.
    --

    -
    ping -f 255.255.255.255 # if only

  6. Re:Best practice? Don't use it! by pauljlucas · · Score: 5, Insightful
    ... most programmers don't have enough training to use a more complex language.
    C is a fairly complex language, e.g.:
    some_func( (void (*)(void*))x );
    C is really just glorified assembly language.
    I don't think this has ever been in distpute by anybody. However, it's still far easier to write in C than assembly.
    I think that C and 'C++ used as C' is the reason alot of commercial software is so bug ridden. Hopefully Java, .NET/.GNU, scripting languages and competent use of modern C++ are starting to change that.
    Java (and other "restrictive" languages) only prevent a small class of errors, e.g., memory leaks. They do nothing to prevent logic or algorithmic errors, and they all have their own gotchas. Try changing what hashcode() returns for an object at run-time after you've put in into a hashmap: have fun finding and debugging that!
    --
    If you reply, do so only to what I explicitly wrote. If I didn't write it, don't assume or infer it.
  7. Better site by fredrikj · · Score: 4, Funny

    Here is a much better article about coding practices. It also covers broad topics, not just C in specific.

  8. Re:Best practice? Don't use it! by jungd · · Score: 2, Interesting

    I've read many times that modern compiled C code or well written C++ code is typically far better than hand written assembly code. I don't know that definitively, however. I'd assume that for small snippets, like specific loops etc., that an assembly programmer could still look at the compiler output and perhaps improve it slightly (if they could understand it!).

    C++ is a super-set of C, so in theory you can get the same output if you want. However, typically program efficiency is at a higher level than specifically optimized loops etc. - e.g. at the level of algorithm choice. In addition, a good C++ matrix class (for example) can do constant folding, loop unrolling and ensure the memory access order of common matrix/vector operations is appropriate for your CPU (via templates) - that you'd be hard pressed to do in C except for very small projects.

    --
    /..sig file not found - permission denied.
  9. Re:Best practice? Don't use it! by sporty · · Score: 2, Interesting

    C++ is a super-set of C, so in theory you can get the same output if you want. However, typically program efficiency is at a higher level than specifically optimized loops etc. - e.g. at the level of algorithm choice. In addition, a good C++ matrix class (for example) can do constant folding, loop unrolling and ensure the memory access order of common matrix/vector operations is appropriate for your CPU (via templates) - that you'd be hard pressed to do in C except for very small projects.


    Ah.. but with C++, you have complications like inheritence and polymophism that can make C++ more complex. I'd suspect OOP systems to be a little less efficient memory-wise at least, to be a bit more ineffficent for this dynamic type thing. But then again, what do I know? :)
    --

    -
    ping -f 255.255.255.255 # if only

  10. Nothing new by McAddress · · Score: 3, Insightful

    This article really does not say anything that any decent programmer does not know. Why we need an article to tell us the basic rules of C is beyond me.

    1. Indent properly.
    2. Make your code readable.
    3. Use good variable names.
    4. Avoid buffer overflows.
    5. Avoid using statements like goto.

    They missed the most basic rule of them all though, convert to C++.

    1. Re:Nothing new by zulux · · Score: 4, Funny


      Ahem...

      1. Indent properly.
      2. Make Your code readable. //this is a great idea
      3. Use_good_variable_names.
      4. Avoid buffer *overflows.
      5. for (;;x = "Avoid using statements like goto.") {;}

      --

      Moneyed corporations, non-working 'poor' and criminal prisoners are turning productive citizens into tax-slaves.

  11. Re:Best practice? Don't use it! by jungd · · Score: 2, Informative

    When writing C++ you have full control over the use of dynamic type info, static or polymorphic method lookup, memory use and object lifetime, etc.

    So, a good programmer can ensure that for performance critical code, none of those expensive features are used (selectively).

    --
    /..sig file not found - permission denied.
  12. Re:Best practice? Don't use it! by _xs_ · · Score: 2, Interesting

    Well, in my job it's common to see C code for almost all our embedded firmware. The only exceptions to this that I've seen is the stuff written in assembly. It's also used to write most of the test software we use. Our department has consciously chosen to limit us to C or VB for development unless you can come up with a truly good reason for using another language. Our department is concerned mostly with testing the products manufactured in our factories. Programming was an interesting little course taught on the side in our electronics courses. From experience we've found that it's easier to train people on one or two languages, rather than have them try to remember (and purchase licenced copies of) VB, VC++, LabWindows, LabView, QuickBasic, HP Vee, Perl... I think that the deficiencies in any language are usually minor. It's more important to build up good techniques and practices like the original author had intended.

    The old saying "It's a poor workman who blames his tools." applies here too.

  13. Obfuscated Error by wbav · · Score: 2, Insightful

    Apparently it was too obfuscated for IBM. The first code example is missing a } at the end of the line.

    --

    =================
    Unix is very user friendly, it's just picky about who its friends are.
  14. peephole by LarryRiedel · · Score: 2, Informative

    FYI, the article seems to be something like a company "basic C coding standards" rather than anything to do with what I understand as "best practices"; maybe a coding tips sheet for an introductory C programming class.

    Larry

    1. Re:peephole by Zarf · · Score: 2, Interesting

      FYI, the article seems to be something like a company "basic C coding standards" rather than anything to do with what I understand as "best practices"; maybe a coding tips sheet for an introductory C programming class.

      From what I've seen in industry there are plenty of PHB's that need to read things like this. I've had PHB's argue that "Everything should be a global variable" because it "makes everything easier." Real businesses need to hear things like this... if it comes from IBM someone just might listen.

      --
      [signature]
  15. use good libraries by nthomas · · Score: 5, Informative
    In addition to the good advice proffered by the article, I should also like to add that using good libraries can make a world of difference.

    For example, for the C program that I'm writing right now, I decided to use GLib -- the base utillity library used by GTK.

    I initially chose it for portability reasons, but soon discovered it had a wealth of cool stuff in it. In addition to providing the standard data structures (trees, hashes, linked lists), it also has a string type ( GString, ) which handles a lot of the string issues that C programmers get bogged down with.

    A lot of the gotchas (buffer overflows, et. al.) mentioned in this article have to do with these string issues, and using GLib's GString data type has enabled me to avoid those.

    There is another library similar to GLib, The Apache Portable Runtime, used in the Apache webserver, and also in Subversion.

    In addition to all this, I'm using XML as the storage format for my program, mostly because libxml takes care of the file parsing issues so I don't have to.

    Bottom line, choose your libraries carefully, they can make a world of difference.

    Thomas

  16. More Tips! by mugnyte · · Score: 5, Funny

    Oh what enlightenment!

    - When you've learned all there is to know about C, find out how to simplify it a bit in C++. Notice the job security and look of awe when you master the ++.

    - After mucking around in these low-density languages, step up to Perl and see how a language built by a task-oriented person stomps one built by a system-oriented person. See your project file sizes shrink before your very eyes!

    - Now take your newfound magic ability to learn new languages and apply it to whipping out pages with PHP and MySQL for all your friends quickly! You'll be the talk of the C crawlers crowd! Hey! Gimmie some content! Aw, forget it - let me just play!

    - Now plumb the depths of (supposed) machine-independent laguanges by writing some Java and finding out what "Sun-certified" means! (hint: Sun owns it)

    - Optional: Head back to school to get a PhD in autoprogramming theory and self-construction methods. Sequester yourself away to your dorm room for endless hours of experiments training a neural net to convert tasks to code using the most efficient method possible.

    - Finally, wrap up your technical life by examining all these related language nuances holistically and achieve the zen of programming: "there is no language"

  17. ah, filks... by pb · · Score: 4, Informative

    You can find many more of these here...

    --
    pb Reply or e-mail; don't vaguely moderate.
  18. Re:I agree, and was it wrong about NULL? by orthogonal · · Score: 3, Informative
    I thought you could use NULL to calculate structure offsets, so with something like

    struct _x {
    int a;
    int b;
    }

    it was legal to say &(((struct _x *)NULL)->b)

    to figure out the offset of b within the structure?



    The compiler may be able to do it; you can not, as it involves dereferencing a null pointer, which makes it undefined according to the C Standard.

    You should use the offsetof macro that the Standard supplies, which your compiler may or may not define as (similar to) the construct you're attempting to use.

    You'd use
    offsetof( struct _x, b ) ;
    add apply it to an instance of struct _x as:

    #include <stddef.h>

    void doit( struct _x* ix ) {
    int i = offsetof( struct _x, b ) ;
    int b = *(int*)( ( (char*)ix ) + i ) ; // or
    int* bp = (int*)( ( (char*)ix ) + i ) ;
    }
  19. Re:Best practice? Don't use it! by Anonymous Coward · · Score: 2, Insightful
    Instruction sets have gotten harder to program directly. Longer pipelines and other CPU optimizations make it advantageous to have instructions in a particular order to prevent register stalls. Computers are excellent at keeping track of information like that.

    In the old days, many CPUs were simple, they only concerned themselves with the current instruction. And, with their lower speeds, compiler optimizations were too slow (and required too much memory) to be worth it. These days, it's not an issue.

  20. Re:Best practice? Don't use it! by Watcher · · Score: 2, Insightful

    This is getting a little rediculous. I'm seeing people confuse exploits with all other bugs. Buffer overruns and the like, which are a side effect of sloppy coding, make up a minority of the total bugs I see on a daily basis in production code. The only reason they are so well known is the consequences. Higher level languages, such as Java and Python, may protect the programmer against the effects of such sloppyness, but they do nothing to protect you against algorithmic bugs, which make up an overwhelming percentage of the bugs I see. Coding in a higher level language may protect you from easily writing exploits, but they do not guarantee you bug free, stable code. Only paying attention to every line you write, and making it as bullet proof and stable as possible, will help safeguard you from all of the many bugs we see. C and C++ are entirely appropriate languages to work in, if they fit the needs of your project.

  21. Re:the best practice by Nick+of+NSTime · · Score: 2, Funny

    No, sucky code is always left by bad programmers.

  22. Re:Best practice? Don't use it! by Gumshoe · · Score: 2, Informative
    C++ is a super-set of C


    Argh! No it isn't! If C++ were a superset, all valid C programs would be valid C++ programs. This is obvious tripe.

    Presumably, this doesn't compile with your C++ compiler.

    #include <stdio.h>

    int
    main(void)
    {
    int class, try, catch;

    class = try + catch;

    printf ("%d\n", class);

    return 0;
    }


  23. Higher and Higher by fm6 · · Score: 2, Insightful
    Actually, C, or any language that talks in expressions rather than a symbolic representation of machine code, counts as "high level". The problems you mention really have more to do with the design philosophy of C than any lack of sophistication in the language.

    Consider C++: you can screw up in all the ways you can screw up with C, and many more besides. I don't think anybody would consider C++ a low-level language.

    I actually agree with your point. I'd just express it differently: C supports the kind of low-level tweaking most programmers shouldn't bother with any more. You should avoid C unless you really need to do this stuff. Otherwise, use a language/library combination that does the low level stuff for you, and probably does it better than you could.

  24. Re:Best practice? Don't use it! by leviramsey · · Score: 2, Insightful

    C++ is effectively a super-set of C, though not a strict superset of C.

    Good enough for you?

  25. Using continue in place of the null statement? by geoswan · · Score: 2, Interesting
    The null body of a for or while loop should be alone on a line and commented so that it is clear that the null body is intentional and not missing code.
    while (*dest++ = *src++) ; /* VOID */

    This could be rewritten as:

    while (*dest++ = *src++)
    continue;
    I believe this is clearer, and less error prone.
    1. Re:Using continue in place of the null statement? by AuraSeer · · Score: 5, Insightful

      It's even clearer to use curly brackets, but the article doesn't mention that either.

      IMO every loop should have brackets, and every 'if' statement too, even when not strictly necessary. They're as good as extra whitespace for visually separating chunks of code, and there's absolutely no downside to including them. I've never understood why many C programmers are so resistant to the idea of extra brackets.

    2. Re:Using continue in place of the null statement? by JamesP · · Score: 3, Funny

      I prefer

      while (*dest++ = *src++) malloc(1000);

      --
      how long until /. fixes commenting on Chrome?
    3. Re:Using continue in place of the null statement? by fnj · · Score: 2, Informative

      I agree with you, but you have invoked a pet peeve of mine.

      [pedantic]

      They are braces, not "curly brackets", let alone "brackets".

      These things have perfectly good names.

      () parentheses
      [] brackets
      {} braces

      [/pedantic]

  26. Re:Best practice? Don't use it! by Gumshoe · · Score: 2, Informative

    "Who modded him informative? Of course it won't work because he uses C++ keywords as variable names!" Err, that was the whole point. It's a valid C program but not a valid C++ program, therefore C++ isn't a superset of C.

  27. Just like UNIX! by Junks+Jerzey · · Score: 3, Insightful

    Although the C language has been around for close to 30 years, its appeal has not yet worn off

    UNIX is the same age, and it hasn't stopped people from thinking that UNIX-like operating systems are the pinnacle of good design.

  28. OTOH, Best practice? Don't use overkill languages by QuasiEvil · · Score: 4, Insightful

    I'm an electrical engineer first and a programmer second. I write everything from BIOS-esque firmware clear up to applications that do data analysis from huge mainframe databases for my company. My language of choice? As close to ANSI C as I can get, though usually I get lazy and use some GNU extensions.

    Now, why on earth would I do something like that? Just to piss off the comp sci types around me? Well, no, but that's a nice side effect.

    Reasons I love/use C:

    - It IS glorified assembly. As such, the compiler tries to be minimally helpful and just lets me do what I want to do.

    - It doesn't allow OOP crap. I won't argue that OOP doesn't have its place, somewhere, but that place isn't in anything I've needed to build yet.
    Why do I hate OOP so much? First and foremost I find it only a tool of obfuscation in the stuff I write. It's much easier to debug procedural code by just following the execution path than wondering what the hell the object that was just instantiated invoked in the constructor, etc. Too much jumping around in the code - basically causes me to forget to look, because it's not intuitive. Same exact reason I hate FORTH (but I'm still fluent in it anyway). I'd rather just have an initializer function called immediately following the declaration of a new variable than having behaviours tacked on.

    - C is faster than C++ if you do everything according to the OOP model that C++ leads you toward. I guarantee my pointer math blows away any "safer" solution in terms of raw speed. It's also just as safe, because all the inputs are bounds checked once so I know they can't exceed certain limits. However, for intelligent mixes of OOP-model code and C-style fun, there's no significant speed difference.

    - Also, C is standard. C is everywhere. I can use it (with code appropriate to the task) on everything from a PIC12xxx series part clear up to our IBM big iron (though that lack of curly braces it quite annoying). As long as I hang out close to ANSI, my code tends to be very portable. As such, I have a library that is used on everything from small, embedded M68k-series processors up to 16-proc Unix boxes and even larger yet mainframes. Completely threadsafe, no memory leaks, and very, very portable.

    Basically, don't use bloat-o-language unless you have a good reason. Remember - CPUs still essentially execute one instruction at a time, mostly in order. Programming is all about moving register 1 to register 2, possibly while performing an arithmetic operation involving register 3.

    I would assert that inappropriate use of OOP model programming, a complete disregard for effeciency in the face of beauty-of-design, and an unholy fascination with language du jour has lead to the sorry, bloated, buggy, slow state of modern applications. IMHO, OOP has lead us down this path, without buying us much. Much except the ability to hire less competent programmers to build their tiny chunk of the application, because everything's overdesigned and all the interfaces are pre-specified, because that's how humans would model the problem. Usually there's little regard for how a machine could best handle the problem.

  29. Rob Pike: Notes on Programming in C by Rick+BigNail · · Score: 2, Insightful
  30. Re:OTOH, Best practice? Don't use overkill languag by Hast · · Score: 2, Informative
    There certainly are areas were OOP or other even more "ivory tower of computer science" ideas are not very useful. Low level programming being the most apparent.

    And processing of large data volumes in a fairly straight forward manner is also very good to do in straight and "simple" code. And C is really good for that. (I'm think eg cryto code, which is both quite math intensive and highly sequential.)

    I won't comment on your views on OOP, while I don't agree with them I don't think anything good will come out of the discussion. (The general idea with all higher level languages is however to map the language as closely as possible to the algorithms as possible. It becomes obvious when you compare eg sorting algorithms in different languages.)


    It IS glorified assembly. As such, the compiler tries to be minimally helpful and just lets me do what I want to do.

    Remember - CPUs still essentially execute one instruction at a time, mostly in order. Programming is all about moving register 1 to register 2, possibly while performing an arithmetic operation involving register 3.

    Now this is just plain wrong. Perhaps you work mainly will micro-controllers but the types of CPUs that are in a typical PC today are not this easy to use at a low level.

    First off, /know your compiler/. If you don't you'll end up doing work that the compiler already does better than you. Both easy stuff like constant propagation and strength reduction (change division by 2 to a shift), as well as more complex things like software pipelining. An optimizing C compiler does a hell of a lot more work then you want to do yourself. (You might want to look into how you use pointers in math operations as you hinted. Pointers often confuse compilers and makes it impossible to optimize as much as with indexed arrays.)

    Second, a typical PC today doesn't even execute x86 asm. It's translated internally to it's own micro code (typically more towards RISC) and executes that. Furthermore it is super-scalar and as such executes several instructions at once. It also moves code around and a bunch of things that will make your brain go numb if you start trying to optimize it by hand. Hell, you can't even access all the registers manually in many cases.

    And that's just looking at the instructions. If you start taking the memory hierarchy into consideration then you'll soon find yourself in a world of confusion.

    Fortunately compilers don't get confused by this. So the way I see it a big importance in the future will be not only how well a language maps to hardware and how it maps to the "algorithms". Of even bigger importance could be how clear things are to the compilers so they can do a proper job. (And in many cases C is very suitable for this today.)
  31. Re:Best practice? Don't use it! by pla · · Score: 2, Informative

    Wow, no down-mods as a troll for you yet?

    Well, let's pretend you didn't mean to start a "better language" war, and address your points.


    Don't even get me started on the 'C is faster than C++ myth'. Only in the hands of an idiot.

    MYTH??? Bring it on, Java-boy. Pick any CPU intensive task, and my C code will DESTROY your best Java code for speed.

    Java does have its uses, including decent type checking and memory management, as you mentioned. Those carry a cost, however. You don't get something for nothing, and with Java, the cost comes in the form of a performance hit.


    most programmers don't have enough training to use a more complex language.

    A curious statement... Would you care to give a few examples of more "complex" languages? Particularly with regards to their greater-than-Turing-completeness compared to C?

    Or do you mean syntactically, in the sense that you find Brainfuck and Malbolge the epitome of a perfect programming language?


    C is really just glorified assembly language.

    Yes and no. For the most part, you can trivially convert C to assembler line-by-line, without too much effort. However, the nice neat flow control mechanisms of C makes it almost immeasurably easier to work with than assembler. Don't get me wrong, I do like asm (just can't beat it for speed), but it works best for drop-in function replacements, not for creating the entire framework of a large application.


    I think C is only still alive because it is supported on most systems,

    Heh... Which, ironically enough, counts as the ONLY reason Java came into existance, and even now that it has "matured", I can build an ANSI-C compatible program on about 6x more platforms than you can run a standard Java app on (whichver "standard" of compatibility you want to pretend exists for Java).

    Now go ahead, suck up the humility and grudgingly point out that, since most Java implementations come written in C, you could build a VM on any machine with a C compiler. But that kinda defeats your own point. (And, at least half of those platforms lack the resources to actually *use* the Java VM, although I have to admit I'd like to see someone try using Java on an embedded 68HC05 with 4k ROM and 256 bytes of RAM, if just for the amusement value).


    Java has its place. C has its place. Scheme has its place. Perl and Python have their place. Tcl/Tk have their place. I won't pretend people can (or rather, "should", since technically anything the machine can do, you can use C to make it do so) use C for everything, if you don't pretend that C hasn't made it as the single most widely supported and generally hardware-wise powerful language for a reason - Namely, it works, and what it does, it does well. You can try to use a hacksaw to cut lumber, but don't blame the hacksaw for doing the job poorly.

  32. Idiosyncratic (and some Wrong) Notes on ... by fnj · · Score: 2, Informative

    Jeeze, there's nothing like taking a bunch of idosyncratic preferences and treating them as best practice, let alone enforcing them at a workplace.

    I note that Pike doesn't even come close to labeling his piece "Best Practice For C Coding" - for which I thank him.

    He does have points that are at least arguably valid, but he lost me at the end.

    "Include files should never include files" ?! Pure bull-freaking-crap hogwash. Rather the opposite is the case! Every include file should include every dependency include file. And order dependency of include files is a no-no. It is quite easy to eliminate all order dependencies, and if I have a religious rule, this is it.