C99 (Analysis Of Some Aspects Of The C99 Standard)
Table of Contents
- c99 (Analysis of some aspects of the c99 standard)
- Compilation
- The C standards
- Some new features included in the standard
- Inline functions
- Intermingled declarations and code
- Variable-length arrays
- A number of new data types
- Other features
Compilation
In old gcc compilers, if you try to compile a program written with the c99 standard, a compilation warning is notified by the compiler. You must use the specific -std option of the gcc compiler, to explicitly specify the standard used in the program you want to compile:
gcc -Wall --pedantic -std=c99 file.cFor new gcc compilers the c99 standard is the default. As a consequence, to know if a program is adherent with the old c90 standard, it must be compiled with the following options:
gcc -Wall --pedantic -std=c90 file.cISO/IEC 9899:1999 http://www.iso.org/iso/catalogue_detail.htm?csnumber=29237
Table which highlights supported features in GCC compilers https://gcc.gnu.org/c99status.html
The C standards
In the following table the C standards are listed. The compiler predefines the following macros, that can be used to check if a given standard is supported and possibly, in the case the standard is not supported, to check if the compiler provides a C90 implementation.
Standard | NAME | Predefined macro |
---|---|---|
ANSI X3.159-1989 | C89 | __STDC__ |
ISO/IEC 9899:1990 | C90 | __STDC__ |
ISO/IEC 9899-1:1994 | C94 | __STDC_VERSION__ = 199409L |
ISO/IEC 9899:1999 | C99 | __STDC_VERSION__ = 199901L |
ISO/IEC 9899:2011 | C11 | __STDC_VERSION__ = 201112L |
Compiling with:
gcc -std=c99 c99_macro_std_version.cthe following program:
c99_macro_std_version.c /* c99: example of macro useful to identify the standard used by the compiler */ #include <stdio.h> int main() { printf("__STDC__: %d __STDC_VERSION__: %ld\n", __STDC__, __STDC_VERSION__); return 0; }the output is:
__STDC__: 1 __STDC_VERSION__: 199901Some new features included in the standard
Inline functions
Function is inline inserted in the code of the program.
Usually it is better to avoid the use of inline functions because:
- gcc is better than you in code optimization
- the generated code is bigger
- you cannot use function pointers
- functions evolve and may no longer be suitable to be declared as inline
- compilation time increases
For more details: http://www.greenend.org.uk/rjk/tech/inline.html
Intermingled declarations and code
Variables can be declared in any point of the source code. In the previous c90 version, the declaration of the variables was restricted to the start of a block.
This possibility is very useful for three main reasons:
- Variable used in the for loops can be initialized directly inside the loop with scope restricted to the loop:
The above code corresponds to the following code written in the c90 standard:
c90_var1.c /* c90: how to restrict the scope of the variable used to manage the cycle in a for loop */ #include <stdio.h> int main() { int i = 123; { int i; for (i=0; i<3; i++) printf("%d ", i); } printf("\nAFTER THE FOR: %d\n", i); return 0; }- Allowing the declaration of variable-length arrays (see in this page in the following)
- Declare the variables exactly where they are needed (limiting the scope of variables is useful, because if a variable exists for a smaller time, the probability of bugs is reduced. As a consequence, a good programming style is to use blocks inside blocks and declare a variable only when it is needed).
Variable-length arrays
Variable-length arrays (VLAs) are classical C arrays, but with a length not declared as a constant expression.
Drawbacks of VLAs are two:
- They are declared as any automatic variable in the stack, which has a limited memory space. As a consequence, the use of VLAs is recommended only when their size is relatively small. As an example, VLAs could be useful for strings.
- The main drawback is that the implementation of VLAs is not mandatory in c11 standard. Therefore, a program that makes use of VLAs could not be compiled by some “new” compilers.
A first easy example is the following, where an array with unknown dimension is read from stdin
c99_variable-length_arrays_1.c /* c99: VLAs, reading a vector with unknown dimension from stdin */ #include <stdio.h> int main() { int l; printf("Insert length: "); scanf("%d", &l); int v[l]; for(int i=0; i<l; i++) scanf("%d", &v[i]); for(int i=0; i<l-1; i++) printf("%d ", v[i]); printf("%d\n", v[l-1]); return 0; }In this second example, VLAs are used in the function my_system to concatenate two strings. The concatenation of the two strings is used as an argument of the system call system.
variable-length_arrays_2.c /* c99: VLAs, system with the concatenation of two strings */ #include <stdio.h> #include <stdlib.h> #include <string.h> int my_system(char *s1, char *s2) { char s[strlen(s1) + 1 + strlen(s2) + 1]; strcpy(s, s1); strcat(s, " "); strcat(s, s2); return system(s); } int main() { my_system("ls", "-l"); return 0; }Reference regarding malloc vs. VLAs: http://www.drdobbs.com/the-new-cwhy-variable-length-arrays/184401444
A number of new data types
long double
Even if the long double type was present from the very beginning in the first version of the C standard, the support in standard libraries of this type starts from the c99 version of the standard.
Constants of type long double are identified by the L or l suffixes at the end of the number (e.g., 12.033134113425422423432L).
The format specifier for printf and scanf functions family is “%Lf” and “%LF”, “%Lg” and “%LG” for a number with up to 6 digits of precision, and “%Le” and “%LE” for the hexadecimal format.
Usually in 32 bits architectures long double are stored with an 80 bits precision, while in a 64 bit architecture they are usually stored with a precision of 128 bits (see https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format). The fact that dimension and characteristics of this type change depending on the architecture and on the compiler leads to compatibility problems when binary files containing long double values are transferred between different PCs.
In the following program some statistics regarding the precision of long double are inspected and an example regarding the printf function is provided:
c99_long_double.c /* c99: some statistics regarding long double and example of the use of the printf function */ #include <stdio.h> #include <float.h> int main() { long double ld = 1342344.42423412442344141232412L; printf("LEN:\n"); printf(" Float len: %zu\n", sizeof(float)); printf(" Double len: %zu\n", sizeof(double)); printf("Long double len: %zu\n", sizeof(long double)); printf("\nNUMBER OF SIGNIFICANT DIGITS:\n"); printf(" Float significant digits = %d\n", FLT_DIG); printf(" Double significant digits = %d\n", DBL_DIG); printf("Long double significant digits = %d\n", LDBL_DIG); printf("\nPRINTF:\n"); printf("%Lf\n", ld); printf("%Lg\n", ld); printf("%Le\n", ld); return 0; }Output:
LEN: Float len: 4 Double len: 8 Long double len: 16 NUMBER OF SIGNIFICANT DIGITS: Float significant digits = 6 Double significant digits = 15 Long double significant digits = 18 PRINTF: 1342344.424234 1.34234e+06 1.342344e+06A good reference regarding float.h library and floating points numbers in general: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/float.h.html
long long int
This new type and the relative unsigned version has been added to the allowed standard C types. In particular:
long long, long long int, signed long long, signed long long int''
- They are equivalent ways to identify signed long long integers. The standard guarantees that in a variable of such type can be stored a number at least in the range [−9223372036854775807, +9223372036854775807], and the minimum size of such a kind of data is 64 bits.
- Constants are identified by the suffixes ll or LL added at the end of the integer constant. Examples are 7ll, 7LL, 07LL, 0x7ll.
- For printf and scanf functions the %lld format specifier is typically used. Other format specifiers are possible, for example for octals or exadecimals numbers (e.g., %llo, %llx, %llX).
unsigned long long, unsigned long long int
- They are the same as long long (i.e., dimension of at least 64 bits), but only for unsigned positive integer numbers. As a consequence, the minimum range of number that can be stored in this type of variables is [0, +18446744073709551615].
- Constants are identified by the suffixes U or u concatenated with the suffixes ll or LL added at the end of the integer constant. Examples are 7Ull, 7LLu, 0x7llu.
- For printf and scanf functions the %llu format specifier is typically used. Other format specifiers are possible, for example for octals or exadecimals numbers (e.g., %llo, %llx, %llX).
The <limits.h> library defines the limits for long long int type:
- long long in the range [LLONG_MIN,LLONG_MAX]
- unsigned long long in the range [0,ULLONG_MAX]
Output:
Range long long: [-9223372036854775808, 9223372036854775807] Range unisigned long long: [0, 18446744073709551615] a: -2 b: 2 -2 is hex FFFFFFFFFFFFFFFE SIZE: 8More details: http://www.drdobbs.com/the-new-c-integers-in-c99-part-1/184401323
boolean (header: stdbool.h)
The new _Bool (or bool defined as macro) type:
- guarantees the possibility of comparison between boolean values (before _Bool a true boolean value in C was a number other than 0, i.e., -15, 1, 123)
- it occupies in memory 1 byte, instead the small integer type (short int) occupies at least 2 bytes.
By including the header stdbool.h the constants true and false are defined.
Casting: (bool)0.5 evaluates to true, whereas (int)0.5 evaluates to 0 (false).
The language guarantees that any two true values will compare equal (which was impossible to achieve before the introduction of the type)
c99_bool_type.c /* c99: the _Bool type */ #include <stdio.h> #include <stdbool.h> /* Header for _Bool */ int main() { _Bool x; bool y; /* bool is a macro with the same meaning of _Bool */ x = true; y = true; if (x==y) printf("Equals\n"); printf("VALUES-> true: %d false: %d\n", true, false); printf("SIZES -> _Bool: %ld short: %ld\n", sizeof(_Bool), sizeof(short)); return 0; }Output:
Equals VALUES-> true: 1 false: 0 SIZES -> _Bool: 1 short: 2complex (header: complex.h)
The c99 standard defines full support to complex numbers through the new complex type defined in complex.h. The three types of complex numbers that can be defined are listed in the following in increasing size order: float complex, double complex and long double complex. I is a constant to identify an imaginary number. Functions creal() and cimag() have been defined to access the real or the imaginary part of a complex number, respectively. All math functions (e.g., sin(), cos(), sqrt()) have an counterpart to be used with complex numbers. Such functions are the same defined in math.h but their name starts with the suffix c (e.g., csin(), ccos(), csqrt()).
The following example should clarify the use of complex numbers:
c99_complex.c /* c99: example regarding complex numbers */ #include <stdio.h> #include <complex.h> #include <tgmath.h> int main(void) { /* Square 1 */ double complex z1 = I * I; printf("I * I = %.1f+%.1fi\n", creal(z1), cimag(z1)); /* Square 2 */ double complex z2 = pow(I, 2); // imaginary unit squared printf("pow(I, 2) = %.1f+%.1fi\n", creal(z2), cimag(z2)); /* Conjugates numbers */ double complex z4 = 1+2*I, z5 = 1-2*I; // conjugates printf("(1+2i)*(1-2i) = %.1f+%.1fi\n", creal(z4*z5), cimag(z4*z5)); /* Square root */ double complex z6=csqrt(-1); printf("sqrt(-1) = %.1f+%.1fi\n", creal(z6), cimag(z6)); }Output:
I * I = -1.0+0.0i pow(I, 2) = -1.0+0.0i (1+2i)*(1-2i) = 5.0+0.0i sqrt(-1) = 0.0+1.0iThe specific header tgmath.h defines a type-generic macro for each mathematical function defined in both math.h and complex.h. Basically, for each math function there are 6 variants: 3 for types float, double and long double, and 3 for types float complex, double complex and long double complex.
A good reference can be downloaded here: http://en.cppreference.com/w/c/numeric/complex
Other features
Other characteristics added by the c99 standard and not discussed here are:
- The use of C++ style comments: //
- Flexible array member: https://en.wikipedia.org/wiki/Flexible_array_member
- Library tgmath.h with defines function for float, double, long double, complex float, complex double and complex long double (only some hints are provided in this guide)
- The snprintf (which is a safe version of the sprintf function) and other new functions
- Others features introduced by the c99 standard can be found in https://en.wikipedia.org/wiki/C99 or in the standard
Page Tools
- Backlinks
- Back to top
Từ khóa » C99 C
-
C99 - Wikipedia
-
[PDF] An Introduction To The C99 Programming Language - Dartmouth CS
-
C99 Features - W3schools
-
What Is C99 In The C Programming Language? - Quora
-
Introduction To The C99 Programming Language : Part I
-
C99
-
What Is The Difference Between C, C99, ANSI C And GNU C?
-
C99 Features In GCC On Fedora
-
C99 - The Open Group Publications Catalog
-
C99 Features As Extensions To C89 - IBM
-
[PDF] Contents - Open-std
-
[PDF] Rationale For International Standard— Programming Languages— C
-
Does Visual Studio 2019 Fully Support C99 Standard For C Code ...
-
C99—A Brief Introduction - C Programming Essentials [Book] - O'Reilly