Jump to content

C syntax

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by 94.128.80.201 (talk) at 08:19, 5 April 2025 (?). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
A snippet of C code which prints "Hello, World!"

The syntax of the C programming language is the set of rules governing writing of software in C. It is designed to allow for programs that are extremely terse, have a close relationship with the resulting object code, and yet provide relatively high-level data abstraction. C was the first widely successful high-level language for portable operating-system development.

C syntax makes use of the maximal munch principle.

Operators

Functions

Syntax

A C function definition consists of a return type (void if no value is returned), a unique name, a list of parameters in parentheses, and various statements:

<return-type> functionName( <parameter-list> )
{
    <statements>
    return <expression of type return-type>;
}

A function with non-void return type should include at least one return statement. The parameters are given by the <parameter-list>, a comma-separated list of parameter declarations, each item in the list being a data type followed by an identifier: <data-type> <variable-identifier>, <data-type> <variable-identifier>, ....

The return type cannot be an array type or function type.

int f()[3];    // Error: function returning an array
int (*g())[3]; // OK: function returning a pointer to an array.

void h()();    // Error: function returning a function
void (*k())(); // OK: function returning a function pointer

If there are no parameters, the <parameter-list> may be left empty or optionally be specified with the single word void.

It is possible to define a function as taking a variable number of parameters by providing the ... keyword as the last parameter instead of a data type ad variable identifier. A commonly used function that does this is the standard library function printf, which has the declaration:

int printf (const char*, ...);

Manipulation of these parameters can be done by using the routines in the standard library header <stdarg.h>.

Function Pointers

A pointer to a function can be declared as follows:

<return-type> (*<function-name>)(<parameter-list>);

The following program shows use of a function pointer for selecting between addition and subtraction:

#include <stdio.h>

int (*operation)(int x, int y);

int add(int x, int y)
{
    return x + y;
}

int subtract(int x, int y)
{
    return x - y;
}

int main(int argc, char* args[])
{
   int  foo = 1, bar = 1;

   operation = add;
   printf("%d + %d = %d\n", foo, bar, operation(foo, bar));
   operation = subtract;
   printf("%d - %d = %d\n", foo, bar, operation(foo, bar));
   return 0;
}

Global structure

After preprocessing, at the highest level a C program consists of a sequence of declarations at file scope. These may be partitioned into several separate source files, which may be compiled separately; the resulting object modules are then linked along with implementation-provided run-time support modules to produce an executable image.

The declarations introduce functions, variables and types. C functions are akin to the subroutines of Fortran or the procedures of Pascal.

A definition is a special type of declaration. A variable definition sets aside storage and possibly initializes it, a function definition provides its body.

An implementation of C providing all of the standard library functions is called a hosted implementation. Programs written for hosted implementations are required to define a special function called main, which is the first function called when a program begins executing.

Hosted implementations start program execution by invoking the main function, which must be defined following one of these prototypes (using different parameter names or spelling the types differently is allowed):

int main() {...}
int main(void) {...}
int main(int argc, char *argv[]) {...}
int main(int argc, char **argv) {...} // char *argv[] and char **argv have the same type as function parameters

The first two definitions are equivalent (and both are compatible with C++). It is probably up to individual preference which one is used (the current C standard contains two examples of main() and two of main(void), but the draft C++ standard uses main()). The return value of main (which should be int) serves as termination status returned to the host environment.

The C standard defines return values 0 and EXIT_SUCCESS as indicating success and EXIT_FAILURE as indicating failure. (EXIT_SUCCESS and EXIT_FAILURE are defined in <stdlib.h>). Other return values have implementation-defined meanings; for example, under Linux a program killed by a signal yields a return code of the numerical value of the signal plus 128.

A minimal correct C program consists of an empty main routine, taking no arguments and doing nothing:

int main(void){}

Because no return statement is present, main returns 0 on exit.[1] (This is a special-case feature introduced in C99 that applies only to main.)

The main function will usually call other functions to help it perform its job.

Some implementations are not hosted, usually because they are not intended to be used with an operating system. Such implementations are called free-standing in the C standard. A free-standing implementation is free to specify how it handles program startup; in particular it need not require a program to define a main function.

Functions may be written by the programmer or provided by existing libraries. Interfaces for the latter are usually declared by including header files—with the #include preprocessing directive—and the library objects are linked into the final executable image. Certain library functions, such as printf, are defined by the C standard; these are referred to as the standard library functions.

A function may return a value to caller (usually another C function, or the hosting environment for the function main). The printf function mentioned above returns how many characters were printed, but this value is often ignored.

Argument passing

In C, arguments are passed to functions by value while other languages may pass variables by reference. This means that the receiving function gets copies of the values and has no direct way of altering the original variables. For a function to alter a variable passed from another function, the caller must pass its address (a pointer to it), which can then be dereferenced in the receiving function. See Pointers for more information.

void incInt(int *y)
{
    (*y)++;  // Increase the value of 'x', in 'main' below, by one
}

int main(void)
{
    int x = 0;
    incInt(&x);  // pass a reference to the var 'x'
    return 0;
}

The function scanf works the same way:

int x;
scanf("%d", &x);

In order to pass an editable pointer to a function (such as for the purpose of returning an allocated array to the calling code) you have to pass a pointer to that pointer: its address.

#include <stdio.h>
#include <stdlib.h>

void allocate_array(int ** const a_p, const int A) {
/* 
 allocate array of A ints
 assigning to *a_p alters the 'a' in main()
*/
    *a_p = malloc(sizeof(int) * A); 
}

int main(void) {
    int * a; /* create a pointer to one or more ints, this will be the array */

 /* pass the address of 'a' */
    allocate_array(&a, 42);

/* 'a' is now an array of length 42 and can be manipulated and freed here */

    free(a);
    return 0;
}

The parameter int **a_p is a pointer to a pointer to an int, which is the address of the pointer p defined in the main function in this case.

Array parameters

Function parameters of array type may at first glance appear to be an exception to C's pass-by-value rule. The following program will print 2, not 1:

#include <stdio.h>

void setArray(int array[], int index, int value)
{
    array[index] = value;
}

int main(void)
{
    int a[1] = {1};
    setArray(a, 0, 2);
    printf ("a[0]=%d\n", a[0]);
    return 0;
}

However, there is a different reason for this behavior. In fact, a function parameter declared with an array type is treated like one declared to be a pointer. That is, the preceding declaration of setArray is equivalent to the following:

void setArray(int *array, int index, int value)

At the same time, C rules for the use of arrays in expressions cause the value of a in the call to setArray to be converted to a pointer to the first element of array a. Thus, in fact this is still an example of pass-by-value, with the caveat that it is the address of the first element of the array being passed by value, not the contents of the array.

Since C99, the programmer can specify that a function takes an array of a certain size by using the keyword static. In void setArray(int array[static 4], int index, int value) the first parameter must be a pointer to the first element of an array of length at least 4. It is also possible to add qualifiers (const, volatile and restrict) to the pointer type that the array is converted to by putting them between the brackets.

Anonymous functions

The anonymous function is not supported by standard C programming language, but supported by some C dialects, such as GCC[2] and Clang.

GCC

The GNU Compiler Collection (GCC) supports anonymous functions, mixed by nested functions and statement expressions. It has the form:

( { return_type anonymous_functions_name (parameters) { function_body } anonymous_functions_name; } )

The following example works only with GCC. Because of how macros are expanded, the l_body cannot contain any commas outside of parentheses; GCC treats the comma as a delimiter between macro arguments. The argument l_ret_type can be removed if __typeof__ is available; in the example below using __typeof__ on array would return testtype *, which can be dereferenced for the actual value if needed.

#include <stdio.h>

//* this is the definition of the anonymous function */
#define lambda(l_ret_type, l_arguments, l_body)        \
  ({                                                   \
   l_ret_type l_anonymous_functions_name l_arguments   \
   l_body                                              \
   &l_anonymous_functions_name;                        \
   })

#define forEachInArray(fe_arrType, fe_arr, fe_fn_body)                                    \
{                                                                                         \
  int i=0;                                                                                \
  for(;i<sizeof(fe_arr)/sizeof(fe_arrType);i++) {  fe_arr[i] = fe_fn_body(&fe_arr[i]); }  \
}

typedef struct
{
  int a;
  int b;
} testtype;

void printout(const testtype * array)
{
  int i;
  for ( i = 0; i < 3; ++ i )
    printf("%d %d\n", array[i].a, array[i].b);
  printf("\n");
}

int main(void)
{
  testtype array[] = { {0,1}, {2,3}, {4,5} };

  printout(array);
  /* the anonymous function is given as function for the foreach */
  forEachInArray(testtype, array,
    lambda (testtype, (void *item),
    {
      int temp = (*( testtype *) item).a;
      (*( testtype *) item).a = (*( testtype *) item).b;
      (*( testtype *) item).b = temp;
      return (*( testtype *) item);
    }));
  printout(array);
  return 0;
}

Clang (C, C++, Objective-C, Objective-C++)

Clang supports anonymous functions, called blocks,[3] which have the form:

^return_type ( parameters ) { function_body }

The type of the blocks above is return_type (^)(parameters).

Using the aforementioned blocks extension and Grand Central Dispatch (libdispatch), the code could look simpler:

#include <stdio.h>
#include <dispatch/dispatch.h>

int main(void) {
  void (^count_loop)() = ^{
    for (int i = 0; i < 100; i++)
      printf("%d\n", i);
    printf("ah ah ah\n");
  };

/* Pass as a parameter to another function */
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), count_loop);

/* Invoke directly */
  count_loop();

  return 0;
}
The code with blocks should be compiled with -fblocks and linked with -lBlocksRuntime

?

See also

Notes

References

  1. ^ Klemens, Ben (2012). 21st Century C. O'Reilly Media. ISBN 978-1449327149.
  2. ^ "Statement Exprs (Using the GNU Compiler Collection (GCC))". gcc.gnu.org. Retrieved 2022-01-12.
  3. ^ "Language Specification for Blocks — Clang 13 documentation". clang.llvm.org. Retrieved 2022-01-14.
General