Why doesn't C11 support lambda functions - c

The new C++11 standard supports lambda functions, which I think is a useful feature. I understand that the C and C++ standards differ from each other but I don't understand why C11 doesn't support lambda functions. I think it could have a lot of use.
Is there a reason why the developers of the C11 standard choose not to include this feature?

2021 update: lambdas based on C++ syntax with minimalist semantics were voted into C23 this year. More details will emerge as the committee pins down precisely what else the feature will bring in from C++ and other implementations.
2016 update: Apple-style lambdas with closures were once again presented to the Working Group at the London 2016 meeting, in a new proposal document that tries to address several of the failings of the previous attempt, tidying up the terminology and explanations and going into much more detail on how closures and lambdas can be made "C-like".
Since the reception was cautiously positive (7-0-9 Yes/No/Abstain), it's looking very possible that something similar to this will make it into the language soon.
The short answer is simply that C doesn't include lambda functions because nobody has yet made an acceptable proposal to the ISO C working group to include lambda functions.
You can take a look at a list of some of the proposals discussed by the working group here: http://www.open-std.org/jtc1/sc22/wg14/www/documents
The only proposal for lambdas of any kind that I can find in that list are Apple's blocks (as demonstrated in Yu Hao's answer), in document N1451. That proposal is discussed further in N1483, which compares it to C++ lambdas, and N1493 and N1542 which are the minutes of the meetings where those documents were presented.
There were several reasons why the proposal in N1451 couldn't be accepted, given in N1542:
initially the committee had difficulty understanding the proposal
it uses incorrect citations and terminology which contradicts the existing C standard
it is apparently vague and incomplete
Apple was in the process of trying to patent the feature (not clear if this is an obstacle to standardisation or not but I would assume so)
A completely new feature with completely new semantics proposed in 2010 had precisely zero chance of being ready in time for 2011, and would have held up the release of C11
Blocks as presented are not compatible with C++11 lambdas
It also looks like they were unconvinced that it was currently demonstrating enough utility. C standardisation apparently tries to be very conservative, and with only one major compiler implementing the feature it's likely that they would want to wait and see how it competes with C++ lambdas, and whether anybody else picks it up. It's not really a "C" feature as opposed to a "Clang" feature until multiple compilers are offering it.
All that said, the committee's votes did apparently lean very slightly in favour of the feature (6-5-4 Yes/No/Abstain), but not enough for the necessary consensus to include it.
As far as I can tell, the other big one, C++11 lambdas, have not been proposed for inclusion into C by anybody; and if you don't ask you don't get.
Any proposal for lambdas in C would add a whole slew of new rules about variable lifetimes and locations and copying and allocation and... etc. For a lot of people this potentially starts to look very un-C-like, with values getting moved around behind the programmer's back or having sudden unexpected changes in their lifespan - avoiding this sort of thing is half the reason people choose to write in C nowadays. So there also has to be a proposal that actually falls in line with C's "philosophy" before it can be taken seriously. I'm sure this can be done, but both of the big proposals so far have been designed for languages with a very different "philosophy" where this sort of thing is less of an obstacle, and don't necessarily reflect C's purpose and character as they currently stand.

C is intended to be a small and simple language. It deliberately omits high-level features when the same things can be done by simpler means. It aims to provide only the basic features that are absolutely necessary for portable programming.
C doesn't have references because they are just pointers. C doesn't have classes, inheritance and virtual functions, because you can just use structs and make vtables yourself using function pointers. It doesn't have a garbage collector because programmers can keep track of memory allocations themselves, it doesn't have templates because they are in fact just macros. If you need exceptions you can use longjmp, and instead of namespaces you simply add prefixes to names.
Adding any of these high-level shortcuts might make programming a little more comfortable, but this comes at the cost of making the language more complicated, which must not be underestimated. It is a slippery slope that directly leads to the mess that C++ has become.
C doesn't have lambda functions because they are not really necessary. Instead you can just use a static function and put the context in a struct.

This is really just my opinion, since I don't know what the committee thinks.
On the one hand, Lisp has been supporting lambda expression since its birth, which is in 1958. The C programming language was born in 1972. So lambda expression actually has a longer history than C. So if you ask why C11 doesn't support lambda expression, the same question can be asked about C89.
On the other hand, lambda expression is always a functional programming thing, and is absorbed to imperative programming languages gradually. Some of the "higher" language (e.g, Java, before the planned Java 8) doesn't support it yet.
Finally, C and C++ are always learning from each other, so maybe it will be in the next C standard. For now, you can take a look at Blocks, a non-standard extension added by Apple. This is an example code from Wikipedia:
#include <stdio.h>
#include <Block.h>
typedef int (^IntBlock)();
IntBlock MakeCounter(int start, int increment) {
__block int i = start;
return Block_copy( ^ {
int ret = i;
i += increment;
return ret;
});
}
int main(void) {
IntBlock mycounter = MakeCounter(5, 2);
printf("First call: %d\n", mycounter());
printf("Second call: %d\n", mycounter());
printf("Third call: %d\n", mycounter());
/* because it was copied, it must also be released */
Block_release(mycounter);
return 0;
}
/* Output:
First call: 5
Second call: 7
Third call: 9
*/

Related

Rationale for pre-C99 C not having initial declarations in for loops?

Why did the original C language not support initial declarations in for loop initializations?
Obviously the original creators, and then the pre-C99 standardizations, didn't specify it that way. But I can't seem to find any rationale for why that design choice was made.
The closest thing to an answer I seem to find is this answer explaining how mixing declarations and code was prohibited in order to allow for compilers to be single-pass back when that was important. At first glance it makes sense that declarations in a for loop statement would have the same/similar problems as declarations mixed with code.
But, pre-C99 C did support declarations at the start of blocks:
{
unsigned int i;
for(i = 0; i < WHATEVER; i += 1)
{
/* ... */
}
}
I don't personally see how the compiler logic for that is substantially different than for this:
for(unsigned int i = 0; i < WHATEVER; i += 1)
{
/* ... */
}
Seems to me that if a compiler can do the former single-pass, it could also do the latter. It might require that a for statement always create a scope block (even if followed by just one statement and not a { ... } block of statements), but I can't think of a way for such semantics to break any other pre-C99 C code (either the for statement is followed by a block in which case it's already "scoped", or it's followed by a single statement, in which case a new declaration wouldn't have been allowed in that single statement anyway).
So, why was this syntax "feature" initially omitted? Am I wrong in thinking that it would've been trivial to support without violating performance goals of the time? Did known language parser/compiler techniques at the time make it seem harder? Did it just get omitted because of minimalist design/mentality, since functionally it was possible to do the same thing (block around for loop)? Or was there an explicit language design reason against it (e.g. how Go initially excluded exceptions because the designers thought that made for a better language)?
Where I've looked
I've tried finding an answer to this here and through general web-search-fu, with no luck: all search terms I thought of seem to be saturated with confused questions about C for loop initial declarations, the "used outside of C99 mode" error message, etc. (Except the search term "rationale", which guided me to useful information, but nothing that answered this specifically).
I searched over this article by Dennis Ritchie himself on developing the language, and didn't spot anything.
I searched through my copy of The C Programming Language (2nd Edition), first reading the actual for loop explaining section, then checking the index for other mentions of the "for"/"for loop". I've read over a couple of other places I thought might mention it, but found nothing.
I don't believe there was any specific decision to exclude such features, nor rationale mounted to do so.
As romantic as it may seem to believe the designers (Kernighan, Ritchie, etc) thought of all the possibilities, and excluded features only after deep and meaningful consideration, the reality is that the early years of designing C (like quite a few other programming languages) followed a much more humble philosophy something like "Start small, don't sweat about adding features unless programmers are being PREVENTED from doing something".
Features like variable initialisation in for loops are programmer convenience - their absence didn't stop things being done. So, even if there was someone begging or campaigning for such a feature (which there probably wasn't), it probably went down in the priority order.
As to how things evolved .....
Before 1999, variable declarations were at the start of blocks in C (code commenced with { and ending at the closing }), not within other statements. This is the way things originally worked in pre-standard (K&R) C, and preceding languages like B (which was actually a cut-down derivative of preceding languages).
Variable declaration/initialisation within a for loop was introduced first into C++. It appeared pretty early on (e.g. Section 19 in the ARM), and was eventually introduced in the first C++ standard that was ratified in late 1998.
There was some discussion in the C standard committee, during the process of drafting the C++ standard (which took a decade) about adopting some features of C++ into C. That discussion was often mostly along the lines of "would anything else in C break if we added this?". A number of compiler vendors had already implemented several such features into their C compilers as optional extensions (or their C compilers were actually C++ compilers, with settings to disable C++ features incompatible with C), so discussion about adding those features was pretty brief. Therefore, those features easily added to C from C++ appeared in the 1999 C standard. Variable declaration/initialisation within a for loop was one of those features.
From that history, there is no evidence of any particular decision or rationale to exclude such features from early C - in short, it probably simply wasn't thought of.

Declare variable as locally as possible

I'm new to Linux kernel development.
One thing that bothers me is a way a variables are declared and initialized.
I'm under impression that code uses variable declaration placement rules for C89/ANSI C (variables are declared at the beginning of block), while C99 relaxes the rule.
My background is C++ and there many advises from "very clever people" to declare variable as locally as possible - better declare and initialize in the same instruction:
Google C++ Style Guide
C++ Coding Standards: 101 Rules, Guidelines, and Best Practices - item 18
A good discussion about it here.
What is the accepted way to initialize variables in Linux kernel?
I couldn't find a relevant passage in the Linux kernel coding style. So, follow the convention used in existing code -- declare variables at beginning of block -- or run the risk of your code seeming out-of-place.
Reasons why variables at beginning of block is a Good Thing:
the target architecture may not have a C99 compiler
... can't think of more reasons
You should always try to declare variables as locally as possible. If you're using C++ or C99, that would usually be right before the first use.
In older C, doing that doesn't fall under "possible", and there the place to declare those variables would usually be the beginning of the current block.
(I say 'usually' because of some cases with functions and loops where it's better to make them a bit more global...)
In most normal cases, declare them in the beginning of the function where you are using them. There are exceptions, but they are rare.
if your function is short enough, the deceleration is far away from the first use anyway. If your function is longer then that - it's a good sign your function is too long.
The reason many C++ based coding standards recommend declaring close to use is that C++ data types can be much "fatter" (e.g. thing of class with multiple inheritances etc.) and so take up a lot more space. If you define such an instance at the beginning of a function but use it only much later (and maybe not at all) you are wasting a lot of RAM. This tends to be much less of an issue in C with it's native type only data types.
There is an oblique reference in the Coding Style document. It says:
Another measure of the function is the number of local variables. They
shouldn't exceed 5-10, or you're doing something wrong. Re-think the
function, and split it into smaller pieces. A human brain can
generally easily keep track of about 7 different things, anything more
and it gets confused. You know you're brilliant, but maybe you'd like
to understand what you did 2 weeks from now.
So while C99 style in-place initialisers are handy in certain cases the first thing you should probably be asking yourself is why it's hard to have them all at the top of the function. This doesn't prevent you from declaring stuff inside block markers, for example for in-loop calculations.
In older C it is possible to declare them locally by creating a block inside the function. Blocks can be added even without ifs/for/while:
int foo(void)
{
int a;
int b;
....
a = 5 + b;
{
int c;
....
}
}
Although it doesn't look very neat, it still is possible, even in older C.
I can't speak to why they have done things one way in the Linux kernel, but in the systems we develop, we tend to not use C99-specific features in the core code. Individual applications tend to have stuff written for C99, because they will typically be deployed to one known platform, and the gcc C99 implementation is known good.
But the core code has to be deployable on whatever platform the customer demands (within reason). We have supplied systems on AIX, Solaris, Informix, Linux, Tru-64, OpenVMS(!) and the presence of C99 compliant compilers isn't always guaranteed.
The Linux kernel needs to be substantially more portable again - and particularly down to small footprint embedded systems. I guess the feature just isn't important enough to override these sorts of considerations.

Which version of C is more appropriate for students to learn- C89/90 or C99?

I'm looking into learning C basics and syntax before beginning Systems Programming next month. When doing some reading, I came across the C89/99 standards. According to Wikipedia,
C99 introduced several new features,
including inline functions, several
new data types (including long long
int and a complex type to represent
complex numbers), variable-length
arrays, support for variadic macros
(macros of variable arity) and support
for one-line comments beginning with
//, as in BCPL or C++. Many of these
had already been implemented as
extensions in several C compilers.
C99 is for the most part backward
compatible with C90, but is stricter
in some ways; in particular, a
declaration that lacks a type
specifier no longer has int
implicitly assumed. A standard macro
STDC_VERSION is defined with value 199901L to indicate that C99 support
is available. GCC, Sun Studio and
other compilers now support many or
all of the new features of C99.
I borrowed a copy of K&R, 2nd Edition, and it uses the C89 standard. For a student, does the use of C89 invalidate some subjects covered in K&R, and if so, what should I look out for?
There is no reason to learn C89 or C90 over C99- it's been very literally superseded. It's easy to find C99 compilers and there's no reason whatsoever to learn an earlier standard.
This doesn't mean that your professor won't force C89 upon you. From the various questions posted here marked homework, I get the feeling that many, many C (and, unfortunately, C++) courses haven't moved on since C89.
From the perspective of a starting student, the chances are that you won't really notice the difference- there's plenty of C that's both C99 and C89/90 to be covered.
Use the C99 standard, it's newer and has more features. Particularly useful may be the bool type in <stdbool.h> and the int32_t etc. family of types; the latter prevents a lot of unportable code that relies on ints having a certain size. AFAIK, it doesn't invalidate K&R, though some example programs may be written in a slightly different style now.
Note that some compilers still don't support C99 properly. I believe that GCC still requires the use of a -std=c99 flag to enable it; many Unix/Linux systems have a c99 command that wraps GCC and enables C99.
The same goes for many university professors. I surprised mine by handing in a program that used bool in my freshman year. He'd never heard of that type in C :)
While I generally agree with the others, it is worth noting that K&R is such a good book that it might be worth learning C from it and then updating your knowledge as you read about the C99 standard.
If you are at student level you probably won't even notice the differences.
Yes, it's a bit odd that you can get a loud consensus that K&R is a great C book, and also a loud consensus that C99 is the correct/current/best version of C. The two positions are incompatible - even if K&R is the best book available to learn "C meaning C99", that just implies the rest are rubbish, or are also hopelessly outdated.
I would advise learning and using C99, but keeping an eye to C89 as you do so. If you use a compiler that has both C89 and C99 compliant modes, then you can write a few bits of C89 just to get an idea of the differences. Then if you ever need to write some code intended to be portable to places that C99 doesn't go, you'll know what to do. If you never have to write any such code, then you've wasted perhaps a day.
Writing C89 properly is actually surprisingly difficult, because getting hold of a copy of the C89 standard is difficult. So, C99 if you can, C89 if for some odd reason you have to, and have some awareness what the difference is. Maybe use K&R to cover the very basics, but get a look at some idiomatic C99 as soon as possible.
As for specific issues to be aware of when reading K&R: there's a list of major changes in the foreword of the standard (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf), although the details aren't laid out there. A lot of them are new features added to C99, so it's not that K&R is wrong, it just may not always use the best tools for a given job. Some of them are quite fiddly things where you should probably consult the standard if you need the details anyway. The rest are things removed from C89, that usually a C99 compiler will tell you about as and when you try to use them.
As a student, that doesn't influence you so much. But if possible, you should find a new C book which covers C99
The term "C89" describes two very different languages:
The language that programmers in 1989 thought the Committee was describing in places where the Standard was ambiguous, and which supported features that were common in pre-existing implementations.
The language that the Committee has since decided that it wanted to have described, which threw compatibility with existing functionality out the
window.
C99 "clarifies" ambiguous parts of the standard by saying that they meant
to have the Standard interpreted in a way that would have broken a substantial
fraction of existing code and made it impossible to perform many tasks as
efficiently as they had been performed in C before 1989.
The right language to program in, for many applications, would be the superset of pre-Standard C, C89, C99, and C11. It's important, however, that anyone programming in that language be clear that they're using that language rather than a shrinking subset which favors speed over reliability.
While I think it's beneficial to know which features are more recent and less likely to be supported by obscure (or intentionally-broken, like MSVC) compilers, there are a few C99 features that you should absolutely use:
snprintf: This is the definitive function for safe and clean string assembly in C. If your compiler is missing it, you can either replace the whole printf subsystem (probably a good idea since most implementations with missing snprintf are also full of (often intentional) bugs in printf behavior), or wrap tmpfile/fprintf/fread/fclose.
stdint.h: If you need fixed-size types (16/32/64-bit), use the standard names int16_t, uint16_t, int32_t, etc. Do not invent your own, and absolutely don't use system-specific ones like INT64 or u32. It just makes your code ugly and hard to integrate and reuse. If your compiler is missing stdint.h, just drop in your own to define the types in terms of the correct-for-your-platform types.
Specifically uint64_t, in place of int foo[2]; or struct { int lo, int hi; } foo; or other hideous legacy hacks to work with 64-bit numbers. Any sane compiler even without C99 support has its own 64-bit types you can use to define int64_t and uint64_t.

Why do new C books not adhere to the C99 standard?

Nearly every (relatively) new book about c programming I've seen doesn't seem to adhere to the C99 standard, or they cover it in an extra chapter. Comming from a Java background, the C99 standard made the migration (well, still migrating ^^) much easier for me, and this probably applies to other languages, too.
It seems like C99 hasn't reached most of the C developers yet. But why?
Short answer: compiler support is slow to get installed and c programmers are a conservative lot who change their behavior slowly.
I strongly suspect it's mainly because MSVC does not attempt to support C99, and quite likely never will. There are a few embedded compilers in the same boat, but they're hardly common enough to matter much individually. AFAIK everyone else is at least trying to implement C99 as much as possible.
There isn't much reason in practice not to use selected features of C99, but if you're going to learn and write to one C standard, and only one, then it must be C89.
Furthermore, it's probably quite difficult and confusing to write an introductory C text which starts out by saying "OK, there are two different standards, and I'm going to use three different colours of text: one for C89, one for C99, and one for both". It's also probably harder to write about C99 for a whole book, and then "take back" a lot of what you've said in an appendix about C89, than it is to write about C89 and then add to it in an appendix about C99.
All speculation, though. Really you'd have to ask the authors of the books you're reading (or perhaps in some cases go against all your programming instincts, and read the foreword ;-))
The risk of switching to a new compiler on an existing code base is generally unknown, but it can be quite painful, its wisest to only switch when you have months of time to shake out any bugs/changes. And for really old code bases, sometimes It's wisest to just never switch at all.
I'd be willing to bet that the majority of projects that use C aren't willing to switch to C99 at all since there's hardly any upside for a large existing code base and quite a bit of potential downside. I worked at one large software house that checked the compilers into th source tree right along side the code and would never switch compilers for a product.

Do you use the TR 24731 'safe' functions? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
The community reviewed whether to reopen this question 9 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
The ISO C committee (ISO/IEC JTC1/SC21/WG14) has published TR 24731-1 and is working on TR 24731-2:
TR 24731-1: Extensions to the C Library Part I: Bounds-checking interfaces
WG14 is working on a TR on safer C library functions. This TR is oriented towards modifying existing programs, often by adding an extra parameter with the buffer length. The latest draft is in document N1225. A rationale is in document N1173. This is to become a Technical Report type 2.
TR 24731-2: Extensions to the C Library - Part II: Dynamic allocation functions
WG14 is working on a TR on safer C library functions. This TR is oriented towards new programs using dynamic allocation instead of an extra parameter for the buffer length. The latest draft is in document N1337. This is to become a Technical Report type 2.
Questions
Do you use a library or compiler with support for the TR24731-1 functions?
If so, which compiler or library and on which platform(s)?
Did you uncover any bugs as a result of fixing your code to use these functions?
Which functions provide the most value?
Are there any that provide no value or negative value?
Are you planning to use the library in the future?
Are you tracking the TR24731-2 work at all?
I have been a vocal critic of these TRs since their inception (when it was a single TR) and would never use them in any of my software. They mask symptoms instead of addressing causes and it is my opinion that if anything they will have a negative impact on software design as they provide a false sense of security instead of promoting existing practices that can accomplish the same goals much more effectively. I am not alone, in fact I am not aware of a single major proponent outside of the committee developing these TRs.
I use glibc and as such know that I will be spared having to deal with this nonsense, as Ulrich Drepper, lead maintainer for glibc, said about the topic:
The proposed safe(r) ISO C library
fails to address to issue completely.
... Proposing to make the life of a
programmer even harder is not going to
help. But this is exactly what is
proposed. ... They all require more
work to be done or are just plain
silly.
He goes on to detail problems with a number of the proposed functions and has elsewhere indicated that glibc would never support this.
The Austin Group (responsible for maintaining POSIX) provided a very critical review of the TR, their comments and the committee responses available here. The Austin Group review does a very good job detailing many of the problems with the TR so I won't go into individual details here.
So the bottom line is: I don't use an implementation that supports or will support this, I don't plan on ever using these functions, and I see no positive value in the TR. I personally believe that the only reason the TR is still alive in any form is because it is being pushed hard by Microsoft who has recently proved very capable of getting things rammed though standards committees despite wide-spread opposition. If these functions are ever standardized I don't think they will ever become widely used as the proposal has been around for a few years now and has failed to garner any real community support.
Direct answer to question
I like Robert's answer, but I also have some views on the questions I raised.
Do you use a library or compiler with support for the TR24731-1 functions?
No, I don't.
If so, which compiler or library and on which platform(s)?
I believe the functions are provided by MS Visual Studio (MS VC++ 2008 Edition, for example), and there are warnings to encourage you to use them.
Did you uncover any bugs as a result of fixing your code to use these functions?
Not yet. And I don't expect to uncover many in my code. Some of the other code I work with - maybe. But I've yet to be convinced.
Which functions provide the most value?
I like the fact that the printf_s() family of functions do not accept the '%n' format specifier.
Are there any that provide no value or negative value?
The tmpfile_s() and tmpnam_s() functions are a horrible disappointment. They really needed to work more like mkstemp() which both creates the file and opens it to ensure there is no TOCTOU (time-of-check, time-of-use) vulnerability. As it stands, those two provide very little value.
I also think that strerrorlen_s() provides very little value.
Are you planning to use the library in the future?
I am in two minds about it. I started work on a library that would implement the capabilities of TR 24731 over a standard C library, but got caught by the amount of unit testing needed to demonstrate that it is working correctly. I'm not sure whether to continue that. I have some code that I want to port to Windows (mainly out of a perverse desire to provide support on all platforms - it's been working on Unix derivatives for a couple of decades now). Unfortunately, to get it to compile without warnings from the MSVC compilers, I have to plaster the code with stuff to prevent MSVC wittering about me using the perfectly reliable (when carefully used) standard C library functions. And that is not appetizing. It is bad enough that I have to deal with most of two decades worth of a system that has developed over that period; having to deal with someone's idea of fun (making people adopt TR 24731 when they don't need to) is annoying. That was partly why I started the library development - to allow me to use the same interfaces on Unix and Windows. But I'm not sure what I'll do from here.
Are you tracking the TR24731-2 work at all?
I'd not been tracking it until I went to the standards site while collecting the data for the question. The asprintf() and vasprintf() functions are probably valuable; I'd use those. I'm not certain about the memory stream I/O functions. Having strdup() standardized at the C level would be a huge step forward. This seems less controversial to me than the part 1 (bounds checking) interfaces.
Overall, I'm not convinced by part 1 'Bounds-Checking Interfaces'. The material in the draft of part 2 'Dynamic Allocation Functions' is better.
If it were up to me, I'd move somewhat along the lines of part 1, but I'd also revised the interfaces in the C99 standard C library that return a char * to the start of the string (e.g. strcpy() and strcat()) so that instead of returning a pointer to the start, they'd return a pointer to the null byte at the end of the new string. This would make some common idioms (such as repeatedly concatenating strings onto the end of another) more efficient because it would make it trivial to avoid the quadratic behaviour exhibited by code that repeatedly uses strcat(). The replacements would all ensure null-termination of output strings, like the TR24731 versions do. I'm not wholly averse to the idea of the checking interface, nor to the exception handling functions. It's a tricky business.
Microsoft's implementation is not the same as the standard specification
Update (2011-05-08)
See also this question. Sadly, and fatally to the usefulness of the TR24731 functions, the definitions of some of the functions differs between the Microsoft implementation and the standard, rendering them useless (to me). My answer there cites vsnprintf_s().
For example, TR 24731-1 says the interface to vsnprintf_s() is:
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdarg.h>
#include <stdio.h>
int vsnprintf_s(char * restrict s, rsize_t n,
const char * restrict format, va_list arg);
Unfortunately, MSDN says the interface to vsnprintf_s() is:
int vsnprintf_s(
char *buffer,
size_t sizeOfBuffer,
size_t count,
const char *format,
va_list argptr
);
Parameters
buffer - Storage location for output.
sizeOfBuffer - The size of the buffer for output.
count - Maximum number of characters to write (not including the terminating null), or _TRUNCATE.
format - Format specification.
argptr - Pointer to list of arguments.
Note that this is not simply a matter of type mapping: the number of fixed arguments is different, and therefore irreconcilable. It is also unclear to me (and presumably to the standards committee too) what benefit there is to having both 'sizeOfBuffer' and 'count'; it looks like the same information twice (or, at least, code will commonly be written with the same value for both parameters).
Similarly, there are also problems with scanf_s() and its relatives. Microsoft says that the type of the buffer length parameter is unsigned (explicitly stating 'The size parameter is of type unsigned, not size_t'). In contrast, in Annex K, the size parameter is of type rsize_t, which is the restricted variant of size_t (rsize_t is another name for size_t, but RSIZE_MAX is smaller than SIZE_MAX). So, again, the code calling scanf_s() would have to be written differently for Microsoft C and Standard C.
Originally, I was planning to use the 'safe' functions as a way of getting some code to compile cleanly on Windows as well as Unix, without needing to write conditional code. Since this is defeated because the Microsoft and ISO functions are not always the same, it is pretty much time to give up.
Changes in Microsoft's vsnprintf() in Visual Studio 2015
In the Visual Studio 2015 documentation for vsnprintf(), it notes that the interface has changed:
Beginning with the UCRT in Visual Studio 2015 and Windows 10, vsnprintf is no longer identical to _vsnprintf. The vsnprintf function complies with the C99 standard; _vnsprintf is retained for backward compatibility.
However, the Microsoft interface for vsnprintf_s() has not changed.
Other examples of differences between Microsoft and Annex K
The C11 standard variant of localtime_s() is defined in ISO/IEC 9899:2011 Annex K.3.8.2.4 as:
struct tm *localtime_s(const time_t * restrict timer,
struct tm * restrict result);
compared with the MSDN variant of localtime_s() defined as:
errno_t localtime_s(struct tm* _tm, const time_t *time);
and the POSIX variant localtime_r() defined as:
struct tm *localtime_r(const time_t *restrict timer,
struct tm *restrict result);
The C11 standard and POSIX functions are equivalent apart from name. The Microsoft function is different in interface even though it shares a name with the C11 standard.
Another example of differences is Microsoft's strtok_s() and Annex K's strtok_s():
char *strtok_s(char *strToken, const char *strDelimit, char **context);
vs:
char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);
Note that the Microsoft variant has 3 arguments whereas the Annex K variant has 4. This means that the argument list to Microsoft's strtok_s() is compatible with POSIX's strtok_r() — so calls to these are effectively interchangeable if you change the function name (e.g. by a macro) — but the Standard C (Annex K) version is different from both with the extra argument.
The question Different declarations of qsort_r() on Mac and Linux has an answer that also discusses qsort_s() as defined by Microsoft and qsort_s() as defined by TR24731-1 — again, the interfaces are different.
ISO/IEC 9899:2011 — C11 Standard
The C11 standard (December 2010 Draft; you could at one time obtain a PDF copy of the definitive standard, ISO/IEC 9899:2011, from the ANSI web store for 30 USD) does have the TR24731-1 functions in it as an optional part of the standard. They are defined in Annex K (Bounds-checking Interfaces), which is 'normative' rather than 'informational', but it is optional.
The C11 standard does not have the TR24731-2 functions in it — which is sad because the vasprintf() function and its relatives could be really useful.
Quick summary:
C11 contains TR24731-1
C11 does not contain TR24731-2
C18 is the same as C11 w.r.t TR24731.
Proposal to remove Annex K from the successor to C11
Deduplicator pointed out in a comment to another question that there is a proposal before the ISO C standard committee (ISO/IEC JTC1/SC22/WG14)
N1967 Field Experience with Annex K — Bounds Checking Interfaces
It contains references to some of the extant implementations of the Annex K functions — none of them widely used (but you can find them via the document if you are interested).
The document ends with the recommendation:
Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.
I support that recommendation.
The C18 standard did not alter the status of Annex K. There is a paper N2336 advocating for making some changes to Annex K, repairing its defects rather than removing it altogether.
Ok, now a stand for TR24731-2:
Yes, I've used asprintf()/vasprintf() ever since I've seen them in glibc, and yes I am a very strong advocate of them.
Why?
Because they deliver precisely what I need over and over again: A powerful, flexible, safe and (relatively) easy to use way to format any text into a freshly allocated string.
I am also much in favor of the memstream functions: Like asprintf(), open_memstream() (not fmemopen()!!!) allocates a sufficiently large buffer for you and gives you a FILE* to do your printing, so your printing functions can be entirely ignorant of whether they are printing into a string or a file, and you can simply forget about how much space you will need.
Do you use a library or compiler with support for the TR24731-1 functions?
If so, which compiler or library and on which platform(s)?
Yes, Visual Studio 2005 & 2008 (for Win32 development obviously).
Did you uncover any bugs as a result of fixing your code to use these functions?
Sort of.... I wrote my own library of safe functions (only about 15 that we use frequently) that would be used on multiple platforms -- Linux, Windows, VxWorks, INtime, RTX, and uItron. The reason for creating the safe functions were:
We had encountered a large number of bugs due to improper use of the standard C functions.
I was not satisfied with the information passed into or returned from the TR functions, or in some cases, their POSIX alternatives.
Once the functions were written, more bugs were discovered. So yes, there was value in using the functions.
Which functions provide the most value?
Safer versions of vsnprintf, strncpy, strncat.
Are there any that provide no value or negative value?
fopen_s and similar functions add very little value for me personally. I'm OK if fopen returns NULL. You should always check the return value of the function. If someone ignores the return value of fopen, what is going to make them check the return value of fopen_s? I understand that fopen_s will return more specific error information which can be useful in some contexts. But for what I'm working on, this doesn't matter.
Are you planning to use the library in the future?
We are using it now -- inside our own "safe" library.
Are you tracking the TR24731-2 work at all?
No.
No, these functions are absolutely useless and serve no purpose other than to encourage code to be written so it only compiles on Windows.
snprintf is perfectly safe (when implemented correctly) so snprintf_s is pointless. strcat_s will destroy data if the buffer is overflowed (by clearing the concatenated-to string). There are many many other examples of complete ignorance of how things work.
The real useful functions are the BSD strlcpy and strlcat. But both Microsoft and Drepper have rejected these for their own selfish reasons, to the annoyance of C programmers everywhere.

Resources