Switching from ansi-c to c-99 discussion
Switching from ansi-c to c-99.
proposal by Sasha Nedvedicky Closed Fri 30 May 2025 5:00PM
The consensus is to switch from ANSI-C to C-99. 50% of voters suggest switching to ANSI-C now. Although not explicitly said, the plan is to merge PR #27659 first. Then we can start getting C-99 features in. If we find a controversy about a particular feature, then we will run a similar type of vote/discussion here.
The next step is to ask Shane to bring this topic to the advisory board and seek approval there. Once the board will approve the PR #27659 will go in.
Thanks to everyone who participated.
The PR-draft here shows my attempt to replace current `BIO_snprintf()` (et.al.) implementation with `snprintf()` found in libc. The deal breaker was missing `va_copy()` which is not part of ansi-c, it's part of C-99. This poll seeks a consensus among OpenSSL committers, so Shane Lontis can bring the topic to Business/Techincal Advisory Committee. Please keep in mind this is about moving away from ansi-c to C-99.
Results
| Results | Option | Votes | % of votes cast | % of eligible voters | |
|---|---|---|---|---|---|
| sooner the better | 8 | 50 | 42 | ||
| yes, but not now. | 7 | 44 | 37 | ||
| I prefer to stick to ansi-c instead of moving C-99 | 1 | 6 | 5 | ||
| Not voted | 3 | 16 |
I presume that
- "Yes but not now" implies 4.0 (no later than spring 2026)
- The voices for (1) and (2) will be summarized making the decision whether we do this step at all
We're using plenty of C99 features already, might as well formalise it.
I am fine with starting the conversation but IMO to be able to decide we have to evaluate which are those legacy platforms (in the list of build targets) that have just C-90 compilers. Then, if we are ready to drop them, we can move to C-99.
I would like to see a list of which platforms in our tiered supported platforms list will be affected by this (because they do not officially have fully compliant c99 toolchains).
Even if the disruption is limited, I think this is a breaking change, and as such should wait for the next major release.
In terms of stability guarantees, as a project , we have committed to a quite high bar so even aiming for next major release, we would need to start making moves now to involve communities in time
I'm all for it, generally speaking. However, switching to c99 may be a breaking change for some platforms, still. Therefore, it would be better to do that switch in 4.0
I would express it differently - that we should pick a subset of the full standard and move forward as quickly as possible. We should have a test program that contains all of what we think should be allowed to be used and allow that to be run on each platform. Before moving or allowing a new C99 feature to be used, we should test that it works across all the primary and secondary platforms and all the platforms in CI (which is a wider set). Full C99 is not widely supported.
The option description doesn't really express my view, but it's the closest option available. We already use C99 features - often with some kind of fallback for if that feature is not available. This seems to work perfectly well and I don't know what the "killer feature" is that makes a move to C-99 a "must have". If there are specific features we want to use then we have a well established approach for introducing them.
the `killer feature` for me is what's found in referenced PR:
va_copy()
s*printf() provided by libc
this will allow us to simplify the implementation of BIO_*print*() functions we have. I strongly believe we are better to drop this code in favor of using libc implementation. The MSVC before 2015 takes slightly different approach to sprint() et. al. but there is a way to deal with it for those old versions.
The platforms which miss sprintf() functions completely should provide their own implementation. I think those platforms should be keeping their own specific patch against OpenSSL which implements sprintf(). I think it is fair assumption. No one should be expecting crypto/ssl library will be providing those fundamentals. That's my opinion.
I don't think the break will be that significant. At least we can try it and see if it's possible to switch for minor releases.
If anything, doing this sooner in a non-LTS release, gives us maximal time to iron out any impediments to having this land in the next LTS, so I would NOT defer this to 4.0. This does not introduce an ABI change, my expectation is that applications built against OpenSSL 3.5 and C90 compilers will still work with libraries built with C99.
I'd like us to switch, but we need to consider which platforms only support ANSI C (so would be dropped), so we should decide soon and probably defer until 4.0. Note that we may want to use a restricted set of C99, as IIRC Microsoft's C compiler wasn't fully compliant even in relatively recent versions.
Agree with Tim that if we're already using some C99 features, we can formalise this and do it quickly (i.e. I guess my position is "pick features that are widely supported and move quickly")
While I agree with the concept of being able to write cleaner code,
It would be unfortunate if we were to introduce features that break some older platforms, so this process would be need to made public and put in an alpha release to give users time to respond.
it would be better to introduce only small changes initially in case they need to be rolled back.
It will clearly be helpful to officially have freedom to use C-99 features as soon as possible.
In terms of compatibility, I like the argumentation given by Viktor:
If anything, doing this sooner in a non-LTS release, gives us maximal time to iron out any impediments to having this land in the next LTS, so I would NOT defer this to 4.0. This does not introduce an ABI change, [...]
I Think it is fair to make the switch since it is probably only a small fraction of deployments that depend on ANSI-C. But it is still breaking compatibility so in my view it has to be done in a major version change.
Note on C99 I think we should actually have an ordered poll on the specific features we want to bring in. Using https://en.wikipedia.org/wiki/C99 as a starting point for the discussion would help.
intermingled declarations and code: variable declaration is no longer restricted to file scope or the start of a compound statement (block)
several new data types, including long long int, optional extended integer types, an explicit Boolean data type, and a complex type to represent complex numbers
variable-length arrays (although subsequently relegated in C11 to a conditional feature that implementations are not required to support)
support for one-line comments beginning with //, as in BCPL, C++ and Java
new library functions, such as snprintf
new headers, such as <stdbool.h>, <complex.h>, <tgmath.h>, and <inttypes.h>
type-generic math (macro) functions, in <tgmath.h>, which select a math library function based upon float, double, or long double arguments, etc.
improved support for IEEE floating point
designated initializers. For example, initializing a structure by field names: struct point p = { .x = 1, .y = 2 };[5]
compound literals. For instance, it is possible to construct structures in function calls: function((struct x) {1, 2})[6]
support for variadic macros (macros with a variable number of arguments)
restrict qualification allows more aggressive code optimization, removing compile-time array access advantages previously held by FORTRAN over ANSI C[7]
universal character names, which allows user variables to contain other characters than the standard character set: four-digit \u0040 or eight-digit hexadecimal sequences \U0001f431
keyword static in array indices in parameter declarations[8]
We are already supporting a subset here - and what my position is we should be willing to accept all of the mainstream features but should check that they work across current CI which covers more than primary and secondary platforms - and to have a test program that lets us know separately if we have an issue. i.e. compile this program and if it compiles then your compile supports the subset we are allowed to use.
References (which I will edit as I locate more):
https://en.cppreference.com/w/c/compiler_support/99
From https://github.com/openssl/technical-policies/pull/50?#issuecomment-1129764075
We currently use those unconditionally:
long long int
flexible array members (not sure if we still do)
snprintf
We use those conditionally:
inttypes (like uint64_t)
inline functions
Things that look useful that we currently don't use:
intermingled declarations and code
booleans
designated initializers
variadic macros
restrict
Unicode (wchar_t)
Things that some people might want to use:
one-line comments using //. The coding style doesn't allow it.
A strong +1 for designated initializers. These would make our tables of algorithms much nicer to read.
What I really like and want to have in our code is declaration of the loop variable in the loop and boolean type.
We should not have an ordered poll. They are designed to get the best single choice which isn't what we're after here. Rather, each feature should be voted on separately either via multiple polls or a "score poll".
@Paul Dale i agree a poll on each item would certainly be the fastest way to seeing what level of interest/support each feature has ...
The way I see it, the question/poll to discuss now is dropping `-ansi` option in favor of `-std=c99`. This is the first step and first decision to be made. The additional decisions will come up once PRs with code changes will be arriving. Then we can individually discuss all c99 features we currently don't (or can not use), be it boolean type, declaration of loop variables, designated initializers etc.
@Sasha Nedvedicky IMO this is the other way around. Changing the CI should happen after we have concrete reasons to drop that CI run, not just "let's be sloppy in which C level is enforced". First we should decide which platforms are we willing to drop, then which C features we want to use and only as the last thing we should drop the -ansi CI job.
But how do we discover pitfalls if we keep `-ansi` safety belt on? I think the only way to move forward is to lift `-ansi` bar and let C99 feature to slowly creep in one-by-one carefully watching the fallout and be ready to step-back/back out if we shoot too far an miss.
@Tomas Mraz, just looking at https://openssl-library.org/policies/general-supplemental/platforms/, I'm willing to bet that only the most aged of the unadopted platforms may not cut it.
@Tim Hudson... Heh, both you and @Kurt Roeckx have mentioned a set of features, of which I would ✅ a large majority
I've just gave a CI try with this PR here:
https://github.com/openssl/openssl/pull/27659
Everything seems to remain green. The PR does 's/-ansi/-std=c99' in github workflow.
For me, setting the base level at C99 means being able to clean away swathes of "compensatory" code in e_os.h, e_os2.h and other places. They... hurt
I also really like syntax like this - if we could use it, it would drastically simplify our code - but I'm not sure to what extent it's supported
@Dmitry Belyavsky, the cleanup attribute is a GNU C extension, so can't be assumed to exist everywhere. I agree it's nice! but...
My view is that we have support to remove the prohibition on more C-99 coming in as a default position. We should check and test that a new feature makes sense to use - but the default is that anything can be proposed and absent hitting demonstrated portability issues on platforms we consider we support, then we can use them. That's my interpretation of the current status.
I think the next step is to get the PR 27659 in so we can start slowly adopting C99 features. Shall we start a new poll about PR 27659?
I think that once this vote concludes and depending on it's result, we can either drop it, delay it or leave it to the normal review process. I don't see a need for a new poll here.
I wonder what was the decision in the end?
The decision at the end was there is no block on using C-99 features in general (there was effectively one in place) and that we can introduce such features as people want to use them and see how each feature goes in terms of supported platforms and where problems arise figure out what approach we want to take.
We should update the coding guideline to reflect this. Current state:
https://github.com/openssl/technical-policies/pull/115
proposed update. I propose conservative approach use C99 for 3.6 and later, 3.5 and older should stick to c90. this basically codifies the current practice.
My thoughts here are that we are probably in agreement to use more C99 features if we know those are okay on all the platforms we currently test and to do it sooner than 4.0 if we don't have a blanket all-C99 decision - i.e. knowing the impact is minimal because we don't test the boundaries might make the view different.
My vote position is on the basis that I think we have been holding back on some C99 features which are widely enough supported now that they are safe enough to use without causing issues.