User Tools

Site Tools


cs:c_language:c99
Return to Home page

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cs:c_language:c99 [2020/11/26 23:18] (current)
Line 1: Line 1:
 +====== c99 (Analysis of some aspects of the c99 standard) ======
 +
 +===== 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:
 +<code bash>
 +gcc -Wall --pedantic -std=c99 file.c
 +</code>
 +
 +For 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: 
 +<code bash>
 +gcc -Wall --pedantic -std=c90 file.c
 +</code>
 +
 +ISO/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:
 +<code bash>
 +gcc -std=c99 c99_macro_std_version.c
 +</code>
 +the following program:
 +<file c 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;
 +}
 +</file>
 +the output is:
 +<code bash>
 +__STDC__: 1   __STDC_VERSION__: 199901
 +</code>
 +
 +===== Some 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:
 +
 +<code c c99_var1.c>
 +/* c99: example of a variable declared inside a for loop */
 +
 +#include <stdio.h>
 +
 +int main() {
 +  int i = 123;
 +  
 +  for (int i=0; i<3; i++)
 +    printf("%d ", i);;
 +
 +  printf("\nAFTER THE FOR: %d\n", i);
 +  
 +  return 0;
 +}
 +</code>
 +The above code corresponds to the following code written in the ''c90'' standard:
 +<code c 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;
 +}
 +</code>
 +  * 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).
 +<code c c99_scope.c>
 +/* c99: limiting the scope of variables declaring them when needed
 +   or declaring them in a block inside a block */
 +
 +#include <stdio.h>
 +
 +int main() {
 +  int x;
 +  x = 2;
 +  /* i cannot be used here */
 +  int i;
 +  i = x;
 +
 +  /* Block inside a block */
 +  {
 +    /* This is another variable, it is not i=x */
 +    int i;
 +    i = 3;
 +
 +    /* At the end of the block i=3 no longer exist */
 +  }
 +  /* i=x still exist */
 +  
 +  return 0;
 +}
 +</code>
 +
 +==== 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
 +<file c 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;
 +}
 +</file>
 +
 +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''.
 +
 +<file c 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;
 +}
 +</file>
 +
 +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:
 +<file c 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;
 +}
 +</file>
 +
 +Output:
 +<code bash>
 +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+06
 +</code>
 +
 +A 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]
 +
 +<code c c99_long_long_int.c>
 +/* c99: the long long int type */
 +
 +#include <stdio.h>
 +#include <limits.h>
 +
 +int main() {
 +  long long int a;
 +  unsigned long long int b;
 +  
 +  printf("Range long long: [%lld, %lld]\n", LLONG_MIN, LLONG_MAX);
 +  printf("Range unisigned long long: [0, %llu]\n", ULLONG_MAX);
 +
 +  a = -2;
 +  b = 2;
 +  
 +  printf("a: %lld   b: %llu\n", a, b);
 +  printf("%3lld is hex %llX\n", a, a);
 +
 +  printf("SIZE: %zu\n", sizeof(long long int));
 +  
 +  return 0;
 +}
 +</code>
 +
 +Output:
 +
 +<code bash>
 +Range long long: [-9223372036854775808, 9223372036854775807]
 +Range unisigned long long: [0, 18446744073709551615]
 +a: -2   b: 2
 + -2 is hex FFFFFFFFFFFFFFFE
 +SIZE: 8
 +</code>
 +
 +More 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)
 +
 +
 +<file c 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;
 +}
 +</file>
 +
 +Output:
 +
 +<code bash>
 +Equals
 +VALUES->  true: 1 false: 0
 +SIZES  -> _Bool: 1 short: 2
 +</code>
 +
 +=== complex (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:
 +<file c 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));
 +      
 +}
 +</file>
 +
 +Output:
 +
 +<code bash>
 +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.0i
 +</code>
 +
 +The 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: ''<nowiki>//</nowiki>''
 +  * 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
 +
  

If you found any error, or if you want to partecipate to the editing of this wiki, please contact: admin [at] skenz.it

You can reuse, distribute or modify the content of this page, but you must cite in any document (or webpage) this url: https://www.skenz.it/cs/c_language/c99?do=diff&rev2%255B0%255D=1457001162&rev2%255B1%255D=1457001284&difftype=sidebyside
/web/htdocs/www.skenz.it/home/data/pages/cs/c_language/c99.txt · Last modified: 2020/11/26 23:18 (external edit)