What are the most useful new features in C99?

c c99
14,255

Solution 1

I'm so used to typing

for (int i = 0; i < n; ++i) { ... }

in C++ that it's a pain to use a non-C99 compiler where I am forced to say

int i;
for (i = 0; i < n; ++i ) { ... }

Solution 2

stdint.h, which defines int8_t, uint8_t, etc. No more having to make non-portable assumptions about how wide your integers are.

uint32_t truth = 0xDECAFBAD;

Solution 3

I think that the new initializer mechanisms are extremely important.

struct { int x, y; } a[10] = { [3] = { .y = 12, .x = 1 } };

OK - not a compelling example, but the notation is accurate. You can initialize specific elements of an array, and specific members of a structure.

Maybe a better example would be this - though I'd admit it isn't hugely compelling:

enum { Iron = 26, Aluminium = 13, Beryllium = 4, ... };

const char *element_names[] =
{
    [Iron]      = "Iron",
    [Aluminium] = "Aluminium",
    [Beryllium] = "Beryllium",
    ...
};

Solution 4

Support for one-line comments beginning with //.

Solution 5

Variable length arrays:

int x;
scanf("%d", &x);
int a[x];
for (int i = 0; i < x; ++i)
    a[i] = i * i;
for (int i = 0; i < x; ++i)
    printf("%d\n", a[i]);
Share:
14,255

Related videos on Youtube

Brian Campbell
Author by

Brian Campbell

At 10, I cut my teeth writing text adventure games in Scheme. In high school, I wrote Mandelbrot set programs on a $10 Commodore 64 from a yard sale, an HP 48 calculator, and a Java 1.0 applet. I've entered 68k machine code by hand into RAM on on a computer I built on a breadboard, and I've implemented an object oriented layer in Scheme for scripting interactive educational multimedia. See my resume on Stack Overflow careers for information on my professional background. All code samples I post on Stack Overflow (other than those excerpted from other projects for explanatory purposes, which should be credited as so) are licensed under the WTFPLv2, or the Creative Commons Attribution-ShareAlike license that all contributions on Stack Overflow are required to be licensed under, at your choice.

Updated on January 28, 2020

Comments

  • Brian Campbell
    Brian Campbell over 4 years

    C99 has been around for over 10 years, but support for it has been slow coming, so most developers have stuck with C89. Even today, I'm sometimes mildly surprised when I come across C99 features in C code.

    Now that most major compilers support C99 (MSVC being a notable exception, and some embedded compilers also lagging behind), I feel that developers who work with C probably ought to know about what C99 features are available to them. Some of the features are just common features that were never standardized before (snprintf, for instance), or are familiar from C++ (flexible variable declaration placement, or single-line // comments), but some of the new features were first introduced in C99 and are unfamiliar to many programmers.

    What do you find the most useful new features in C99?

    For reference, the C99 standard (labelled as a draft, but identical to the updated standard, as far as I know), the list of new features, and the GCC C99 implementation status.

    One feature per answer, please; feel free to leave multiple answers. Short code examples demonstrating new features are encouraged.

    • Alok Singhal
      Alok Singhal over 14 years
      There should be a similar wiki for features that people hate in C99!
    • Brian Campbell
      Brian Campbell over 14 years
      Well, there was a question about harmful or unsupported C99 features stackoverflow.com/questions/1898890/…
    • Alok Singhal
      Alok Singhal over 14 years
      Thanks. You should change the link text to indicate that it's a draft, not the actual standard, and link to n1256 while you're at it :-). BTW, looking at gcc.gnu.org/c99status.html, I wouldn't say most of C99 is supported by gcc. And since gcc is one of the most widely used C compilers, ...
    • Exectron
      Exectron over 14 years
      Note that in the embedded processor arena, C99 may still not be well supported.
    • Brian Campbell
      Brian Campbell over 14 years
      @Alok I would call that level of support most of the features; I suppose it depends on how you define it, but I think most of the significant features that people want to use are supported, leaving aside a few library issues. @Craig Fair enough, added a disclaimer about embedded compilers.
    • Jonathan Leffler
      Jonathan Leffler over 14 years
      Of course, the biggest problem with C99 is that the MSVC compilers do not support many (any?) of the most useful features listed below. This hobbles people who have to write code that works on both Unix and Windows.
    • Brian Campbell
      Brian Campbell over 14 years
      Of course; hence the "but one" in my original question. Now, you don't have to compile with MSVC on Windows; you can use MinGW, or the Intel C Compiler, or any of a number of other compilers that do support C99.
    • new123456
      new123456 almost 13 years
      Wow - it's amazing, being only a once-in-a-while C programmer, how much I have actually used these features from a standard that has yet to be fully implemented. +1 for the edifycation!
  • helpermethod
    helpermethod over 14 years
    Besides, it narrows the scope of the int variable, which is always a good thing ^^
  • figurassa
    figurassa over 14 years
    That would be my pick as well.
  • daf
    daf over 14 years
    In practice, GCC usually ignores the inline keyword when deciding which functions to inline, and automatically inlines things based on its own heuristics unless you force it to do otherwise.
  • Brian Campbell
    Brian Campbell over 14 years
    Very true. I was going to add this answer myself if no one else did.
  • Brian Campbell
    Brian Campbell over 14 years
    Yep, I just used these the other day when trying to explain to someone how floating point numbers work in another Stack Overflow question.
  • Kevin L.
    Kevin L. over 14 years
    Best hex phrase since DE:AD:BE:EF:CA:FE.
  • caf
    caf over 14 years
    daf: inline still helps though, because it allows you to define the function in more than one translation unit - so you can put it in a header file, which gives cross-module inlining opportunities.
  • L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
    L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ about 14 years
    whoever thought of this is pure genious
  • slebetman
    slebetman almost 14 years
    +1 ALL compilers I know already support this. It's about time it's mentioned in the standard.
  • slebetman
    slebetman almost 14 years
    +1 for finally making this kosher. It's in every TCP/IP socket code I've ever seen.
  • supercat
    supercat over 13 years
    Indeed, I would consider it far more kosher than the common trick of using buf[1] and subtracting 1 from the malloc size. The trick may be common, but I would regard it as Undefined Behavior (proper would be using buf[MAX_SIZE] and subtracting MAX_SIZE from the malloc size) since a compiler's generated indexing code may depend upon the perceived size of buf[].
  • supercat
    supercat over 13 years
    I'm not so keen on this. To my mind, variables should not only be brought into scope when needed, but removed from scope when not needed. Variables mid-block almost invariably hang around in scope longer than they should.
  • u0b34a0f6ae
    u0b34a0f6ae over 12 years
    That is a compelling demonstration. There is a huge amount of enum-tables with corresponding string-tables out there.
  • Cole Tobin
    Cole Tobin over 11 years
    @Oliver <sarcasm>but then the instructions sub esp, 4 and add esp, 4 are removed!</sarcasm>
  • Cole Tobin
    Cole Tobin over 11 years
    Well, MS doesn't like to do this
  • Jonathan Leffler
    Jonathan Leffler over 11 years
    @ColeJohnson: If you look carefully at the second example, you will observe that the initializers are listed out of order — but will work correctly. That can't be done simply with defines. The first example initializes only index 4 of the array; that can't be done simply with defines, either.
  • Cole Tobin
    Cole Tobin over 11 years
    @daf inline __attribute__((force_inline))
  • johnny
    johnny about 11 years
    It should also be noted that using the same index more than once will override the first usage with the second - see my question here, for example: stackoverflow.com/questions/16742467/…
  • Pacerier
    Pacerier almost 11 years
    What's decafbad supposed to mean?
  • Brian Campbell
    Brian Campbell almost 11 years
    @Pacerier It's just an arbitrarty hexadecimal constant used to illustrate the example. But for humor value, it spells "decaf bad", implying that decaffeinated coffee is inferior to the real thing.
  • Pacerier
    Pacerier almost 11 years
    ok, I can't relate to their humor...
  • Jarosław Bielawski
    Jarosław Bielawski over 10 years
    No, bool in C99 coerces the value assigned to the variable to be always 1 or 0. That's why you have to be carefull if you have code that runs on a C99 compiler and on an older one with "simulated" booltype. Using !! will make that portable. v = !!5; has the same semantic, but is not as readable.
  • Ryan Haining
    Ryan Haining about 10 years
    @supercat you'd prefer int a; int b; a = f(); b = g(); to int a = f(); int b = g(); ? declaring a variable close to where it gets initialized is huge for reducing errors.
  • supercat
    supercat about 10 years
    @RyanHaining: Alternatively, create a nested scope block (I just wish there was a standard syntax which said "this block is just for scoping"; one can use easily use a null macro for that purpose, but that seems a bit ugly.
  • phuclv
    phuclv over 9 years
    will it print 1 when assigning an even number like 6?
  • Jarosław Bielawski
    Jarosław Bielawski over 9 years
    Yes. Any non zero value wil be replaced by 1.
  • Z boson
    Z boson about 9 years
    You really think VLA arrays are that great? C11 makes them optional.
  • Andrew D'Addesio
    Andrew D'Addesio over 8 years
    Just don't forget to apply input sanitation to prevent a stack overflow (or stack corruption, if x is negative): if (x < 0) x = 0; else if (x > 1024) x = 1024;
  • supercat
    supercat over 7 years
    C isn't really well designed for the concept of rounding modes, since they mean that floating-point math needs to be treated as having side-effects. Having something better than "hope-for-the-best" floating-point semantics is useful, but I don't know how many implementations really honor all the requirements of Annex F.
  • alx
    alx about 5 years
    @supercat There is a standard syntax for that: /* this block is just for scoping */ { } /* scope */ :)
  • supercat
    supercat about 5 years
    @CacahueteFrito: I think if(1) /* Scoping block */ { } is a bit better, but a bigger issue is that scoping and control are orthogonal concepts. While there are times when it makes sense to scope things within a loop, it's more often useful to have things scoped just around the loop, and there are also many times when code will create objects to holding values that will be needed in the creation of longer-lived objects, but never after that (e.g. float dx=x2-x1, dy=y2-y1; float distance = sqrt(dx*dx+dy*dy);. There's no reason dx and dy should need to be kept in scope.
  • AlphaGoku
    AlphaGoku almost 5 years
    It should inturn allocate memory on stack for 4 right?
  • xdavidliu
    xdavidliu about 2 years
    I don't get it, why doesn't it print v=1? What happened to v=?
  • Jarosław Bielawski
    Jarosław Bielawski about 2 years
    Of course it will print v=1. 12 years before someone sees the obvious bug, nice. :-)
  • Jarosław Bielawski
    Jarosław Bielawski about 2 years
    Extremely valuable feature. I do not share @supercat reservations. By defining and initialising the variable where it is needed (in association with for( declarations) I have managed to reduce significantly the complexity of the code. In 2010 I would have not known, now after converting several thousands of line of code, I was surprised at the positive effect it has on the code quality. Several wrong initialisation bugs have also been found this way.
  • Jarosław Bielawski
    Jarosław Bielawski about 2 years
    wrong initialisation bugs = variable defined at fn level and initialised with 0 or NULL, then the first usage is done somewhere down in the function but its init value should have been something else. I was extremely surprised how often this bug was present in our code base.
  • supercat
    supercat about 2 years
    @PatrickSchlüter: Would it not be useful, in something like my example, to be able to have dx and dy leave scope while keeping distance within?
  • Jarosław Bielawski
    Jarosław Bielawski about 2 years
    @supercat yes it would but my experience is that most of the time, it does. As very often the variable you move from the function scope, is a variable that can be defined inside an existing if or loop block (for(int i; being very often encountered). The feature is a net positive even if it is 100% theoretically not perfect.