Back to C Programming
2026-04-146 min read

generic association

Learn generic association step by step with clear examples and exercises.

Title: Mastering Generic Associations in C Programming - An In-depth Guide

Why This Matters

In this full guide, we will delve into the intricacies of generic associations, a powerful feature introduced in C11 that allows you to choose one of several expressions at compile time based on the type of an expression. This feature is crucial for writing more flexible and reusable code, especially when dealing with templates or functions that work with different data types.

Prerequisites

Before diving into generic associations, it's essential to have a solid understanding of the following topics:

  1. Basic C syntax and control structures (e.g., loops, conditionals)
  2. Pointers and arrays
  3. Functions and function pointers
  4. Structures and unions
  5. Preprocessor directives (#include, #define)
  6. Understanding of type qualifiers (const, volatile)
  7. Familiarity with basic arithmetic and logical operators
  8. Comprehension of C's type promotion rules
  9. Knowledge of operator precedence and associativity
  10. Proficiency in using debugging tools to identify and resolve issues
  11. Understanding of enumerations (enums) and bitfields
  12. Familiarity with predefined data types such as char, short, int, long, float, double, etc.
  13. Knowledge of C's standard libraries, including math functions and string handling functions

Core Concept

Syntax

The syntax for using generic associations is as follows:

_Generic(controlling-expression,
association-list)

Here, controlling-expression is any expression (except for the comma operator) whose type must be compatible with one of the types specified in the association-list. The list itself is a comma-separated list of associations, each of which has the syntax:

type-name : expression

type-name represents any complete object type that isn't variably modified (i.e., not VLA or pointer to VLA). expression is any expression (except for the comma operator) of any type and value category. There may be only one association that uses the keyword default.

Explanation

First, the type of controlling-expression undergoes lvalue conversions. The conversion discards the top-level cvr-qualifiers (const, volatile) and atomicity and applies array-to-pointer/function-to-pointer transformations to the type of the controlling expression without initiating any side-effects or calculating any values.

The converted type is then compared with the types specified in the association-list. If the type is compatible with one of the types in the list, the corresponding expression associated with that type will be evaluated and returned as the result of the _Generic expression. If no compatible types are found and the default association is not used, the program will not compile.

Keywords

The only keyword used in generic associations is default, which can be used to specify a default action if none of the other associations match the type of the controlling expression.

Worked Example

Let's consider an example where we want to create a function that calculates the square of a number, but supports both integers and floating-point numbers:

#include <stdio.h>
#include <math.h> // Include math library for pow function

long long int square_int(int num) {
return (long long int)(num * num);
}

double square_float(float num) {
return pow(num, 2.0);
}

// Using generic associations to create a single function for both integers and floating-point numbers
long long int or_double square( _Generic((int*)&num,
int : square_int,
float : square_float,
double : square_float, // Adding support for double precision floating-point numbers
default : square_int) ) {
return num; // This line is added to silence the compiler warning about unused variables
}

int main() {
int a = 5;
float b = 3.14;
double c = 2.71828;

printf("Square of integer: %lld\n", square((int*)&a));
printf("Square of floating-point (float): %.2f\n", square((float*)&b));
printf("Square of floating-point (double): %.6f\n", square((double*)&c));

return 0;
}

In this example, we define two separate functions square_int and square_float for integers and floating-point numbers, respectively. Then, we use generic associations to create a single function square that can handle both types. The casting of the input variable num to an integer pointer allows us to pass it as the controlling expression to the _Generic function.

Note:

In the above example, we have added a type cast to ensure that the result of the multiplication operation between two integers does not overflow and is correctly converted to the appropriate data type (long long int in this case). This highlights the importance of understanding C's type promotion rules when working with generic associations.

Common Mistakes

  1. Forgetting to cast the controlling expression: Since the controlling expression must be a pointer type, it's essential to cast the input variable to an appropriate pointer type before passing it to the _Generic function.
  1. Using incompatible types: Make sure that the types specified in the association-list are not compatible with each other. If they are, the program will not compile.
  1. Not providing a default association: If none of the associations match the type of the controlling expression and no default association is provided, the program will not compile.
  1. Misunderstanding type promotions: Be aware that C's type promotion rules can lead to unexpected results when using generic associations. Always ensure that the types involved in the expressions are compatible and properly casted.
  1. Ignoring const and volatile qualifiers: Remember that lvalue conversions discard top-level cvr-qualifiers, so you may need to handle const and volatile qualifiers explicitly in your code when using generic associations.
  1. Forgetting to include necessary libraries: If your generic association involves functions from standard libraries (e.g., math library), make sure to include the appropriate header files.
  1. Not handling overflow or underflow: When dealing with integer arithmetic, be aware of potential overflow or underflow issues and handle them appropriately in your code.

Practice Questions

  1. Write a generic function print_type that can print the type of any variable passed to it using _Generic. The function should work for both integers and floating-point numbers, as well as pointers to these types.
  1. Modify the square example from above to also support double precision floating-point numbers (double).
  1. Implement a generic function max_value that returns the maximum value between two arguments of any numeric type (int, float, or double).
  1. Write a generic function print_array that can print an array of any numeric type (int, float, or double) using _Generic. The function should accept the array and its size as parameters.
  1. Implement a generic function find_odd that finds the first odd number in an array of integers using _Generic. If no odd numbers are found, the function should return -1.

FAQ

  1. Can I use generic associations with user-defined types?

Yes, you can use generic associations with user-defined types as long as they are complete object types and not variably modified.

  1. What happens if the controlling expression is of a type that doesn't match any association in the list?

If the controlling expression is of a type that doesn't match any association in the list and no default association is provided, the program will not compile.

  1. Can I use the comma operator as the controlling expression with generic associations?

No, you cannot use the comma operator as the controlling expression with generic associations. The type of the controlling expression must be compatible with one of the types specified in the association-list.

  1. Is it possible to use _Generic with function pointers or macros?

No, _Generic can only be used with expressions that have a complete object type. Function pointers and macros do not meet this requirement.

  1. Are there any limitations on the number of associations in the association-list?

There is no specific limit on the number of associations in the association-list, but the list must be terminated by a semicolon (;). However, using too many associations can make the code difficult to read and maintain.

  1. Can I use _Generic with bitfields or enumerations?

Yes, you can use _Generic with bitfields and enumerations as long as they are complete object types.

  1. Is it possible to use _Generic for string handling operations?

While it's not recommended due to the complexity of C strings, you can use _Generic for simple string comparisons or length calculations if needed. However, for more complex string operations, consider using libraries such as string.h or writing your own string functions.