Undefined Behavior in C and C++
Last Updated :
29 Mar, 2024
When we run a code, sometimes we see absurd results instead of expected output. So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended. Whenever the result of an executing program is unpredictable, it is said to have undefined behavior.
As a C programmer, understanding undefined behavior is very important for optimal coding and for the program to yield a good efficiency, especially when it comes to there are C codes embedded in system design.
Examples:
Division By Zero
int val = 5;
return val / 0; // undefined behavior
Memory accesses outside of array bounds
int arr[4] = {0, 1, 2, 3};
return arr[5]; // undefined behavior for indexing out of bounds
Signed integer overflow
int x = INT_MAX;
printf("%d", x + 1); // undefined behavior
Null pointer dereference
val = 0;
int ptr = *val; // undefined behavior for dereferencing a null pointer
Modification of string literal
char* s = "geeksforgeeks";
s[0] = 'e'; // undefined behavior
Accessing a NULL Pointer, etc.
int* ptr = NULL;
printf("%d", *ptr); // undefined behavior for accessing NULL Pointer
Sometimes compilers may diagnose simple errors, however, sometimes they are not designed to diagnose the undefined behavior.
Following are some C/C++ programs that showcase undefined behavior:
Program 1:
C++
// C++ Program to demonstrate
// division by 0
#include <iostream>
using namespace std;
int main()
{
int x = 25, y = 0;
int z = x / y;
cout << z;
return 0;
}
// This code is contributed by sarajadhav12052009
C
// C Program to demonstrate
// division by 0
#include <stdio.h>
// Driver Code
int main()
{
int x = 25, y = 0;
int z = x / y;
printf("%d", z);
return 0;
}
Program 2:
C++
// C++ Program to demonstrate
// Uninitialized variables
#include <iostream>
using namespace std;
int main()
{
bool val;
if (val)
printf("TRUE");
else
printf("FALSE");
}
// This is contributed by sarajadhav12052009
C
// C Program to demonstrate
// Uninitialized variables
#include <stdio.h>
// Driver Code
int main(void)
{
typedef enum {False, True} bool;
bool val;
if (val)
printf("TRUE");
else
printf("FALSE");
}
Program 3:
C++
// C++ Program to demonstrate
// accessing value of NULL pointer
#include <iostream>
using namespace std;
int main()
{
int* ptr = NULL;
cout << *ptr;
return 0;
}
// This code is contributed by sarajadhav12052009
C
// C Program to demonstrate
// accessing value of NULL
// pointer
#include <stdio.h>
// Driver Code
int main()
{
int* ptr = NULL;
printf("%d", *ptr);
return 0;
}
Program 4:
C++
// C++ program to demonstrate
// accessing out of bound
#include <iostream>
using namespace std;
int main()
{
int arr[5];
// We access arr[5] in last iteration.
for (int i = 0; i <= 5; i++)
cout << arr[i];
return 0;
}
// This code is contributed by sarajadhav12052009
C
// C program to demonstrate
// accessing out of bound
#include <stdio.h>
// Driver Code
int main()
{
int arr[5];
// We access arr[5] in last iteration.
for (int i = 0; i <= 5; i++)
printf("%d ", arr[i]);
return 0;
//edited by malav.shubham17
}
Program 5:
C++
// C++ Program to demonstrate going
// beyond limit of signed int
#include <iostream>
#include <climits>
using namespace std;
int main()
{
int x = INT_MAX;
cout << x + 1;;
return 0;
}
// This code is contributed by sarajadhav12052009
C
// C Program to demonstrate going
// beyond limit of signed int
#include <stdio.h>
#include <limits.h>
// Driver Code
int main()
{
int x = INT_MAX;
printf("%d", x + 1);
return 0;
}
Program 6:
C++
// C++ Program to demonstrate trying to
// modify a string literal
#include <iostream>
using namespace std;
int main()
{
char* s = "geeksforgeeks";
s[0] = 'e';
return 0;
}
// This code is contributed by sarajadhav12052009
C
// C Program to demonstrate trying to
// modify a string literal
#include <stdio.h>
// Driver Code
int main()
{
char* s = "geeksforgeeks";
s[0] = 'e';
return 0;
}
program 7:
C++
// c++ program to demonstrate undefined behavior
// of combination of post and pre increment
#include <iostream>
using namespace std;
int main()
{
// code
int p = 4;
cout << ++p * p++ << endl;
return 0;
}
C
// c program to demonstrate undefined behavior
// of combination of post and pre increment
#include <stdio.h>
int main()
{
// code
int p = 4;
printf("%d", ++p * p++);
return 0;
}
Program:8
C++
// c++ program to demonstrate undefined behavior
// of combination of post and post increment
#include <iostream>
using namespace std;
int main()
{
// code
int p = 4;
cout << ++p * ++p;
return 0;
}
C
// c program to demonstrate undefined behavior
// of combination of post and post increment
#include <stdio.h>
int main()
{
// code
int p = 4;
printf("%d", ++p * ++p);
return 0;
}
Program 9:
C++
// C++ Program to demonstrate modifying a variable
// multiple times before a defined sequence point
#include <iostream>
using namespace std;
int main()
{
int i = 8;
int p = i++ * i++;
cout << p;
}
// This code is contributed by sarajadhav12052009
C
// C Program to demonstrate modifying a variable
// multiple times before a defined
// sequence point
#include <stdio.h>
// Driver Code
int main()
{
int i = 8;
int p = i++ * i++;
printf("%d\n", p);
}
Explanation: The program produces 72 as output in most of the compilers, but implementing software based on this assumption is not a good idea.
The output of all of the above programs is unpredictable (or undefined). The compilers (implementing the C/C++ standard) are free to do anything as these are undefined by the C and C++ standards.
Language like Java, trap errors as soon as they are found but languages like C and C++ in a few cases keep on executing the code in a faulty manner which may result in unpredictable results. The program can crash with any type of error message, or it can unknowingly corrupt the data which is a grave issue to deal with.
Importance of knowing about Undefined Behaviour: If a user starts learning in a C/C++ environment and is unclear about the concept of undefined behavior then that can bring plenty of problems in the future while debugging someone else's code might be actually difficult in tracing the root to the undefined error.
Risks and Disadvantages of Undefined Behaviour
- The programmers sometimes rely on a particular implementation (or compiler) of undefined behavior which may cause problems when the compiler is changed/upgraded. For example, the last program produces 72 as output in most of the compilers, but implementing software based on this assumption is not a good idea.
- Undefined behaviors may also cause security vulnerabilities, especially due to the cases when an array out of bound is not checked (causes buffer overflow attack).
Advantages of Undefined Behaviour
- C and C++ have undefined behaviours because it allows compilers to avoid lots of checks. Suppose a set of code with a greater performing array need not keep a look at the bounds, which avoids the need for a complex optimization pass to check such conditions outside loops. The tightly bound loops and speed up the program from thirty to fifty percent when it gains an advantage of the undefined nature of signed overflow, which is generally offered by the C compiler.
- We also have another advantage of this as it allows us to store a variable's value in a processor register and manipulate it over time that is larger than the variable in the source code.
- It also helps in wrap-around then compile-time checks which would not be possible without the greater knowledge of the undefined behaviour in the C/C++ compiler.
More Examples of undefined behavior
- Sequence Points in C | Set 1
- “delete this” in C++
- Passing NULL to printf in C
- Accessing array out of bounds in C/C++
- Use of realloc()
- Execution of printf with ++ operatorsVirtual destruction using shared_ptr in C++
- Virtual Destructor
Similar Reads
Unspecified behavior in C/C++ with Examples Unspecified Behavior terminology is used by users of C and C++. It is defined as Annex-J of C11 standard. Let us learn about this terminology in depth. Type 1. Evaluation order of function arguments: A program is said to have an unspecified behavior when the standard provides two or more possibiliti
7 min read
Unusual behaviour with character pointers In C++, cout shows different printing behaviour with character pointers/arrays unlike pointers/arrays of other data types. So this article will firstly explain how cout behaves differently with character pointers, and then the reason and the working mechanism behind it will be discussed. Example 1:
5 min read
Can main() be overloaded in C++? Predict the output of following C++ program. C highllight=12-5 #include <iostream> using namespace std; int main(int a) { cout << a << "\n"; return 0; } int main(char *a) { cout << a << endl; return 0; } int main(int a, int b) { cout << a << "
2 min read
Name Mangling and extern "C" in C++ C++ supports function overloading, i.e., there can be more than one function with the same name but, different parameters. How does the C++ compiler distinguish between different functions when it generates object code - it changes names by adding information about arguments. This technique of addin
3 min read
Increment Operator Behavior When Passed as Function Parameters in C++ In C++, an increment operator is used to increment the value of the variable by 1. The symbol ++ is used to represent the increment operator. There are two types of increment operators: Pre-Increment Operator: This form of increment operator increases the value of the variable by 1 before assigning
3 min read
Incompatibilities between C and C++ codes The C/C++ incompatibilities that cause most real problems are not subtle. Most are easily caught by compilers. This section gives examples of C code that is not C++ : 1) In C, functions can be defined using a syntax that optionally specifies argument types after the list of arguments: C // C code th
3 min read
Pre-increment and Post-increment in C/C++ In C/C++, Increment operators are used to increase the value of a variable by 1. This operator is represented by the ++ symbol. The increment operator can be classified into two types:Pre-Increment OperatorPost-Increment OperatorPre and Post Increment Operator in C/C++ The pre and post-increment ope
4 min read
Difference between tellg and tellp in C++ In this article, we will discuss the functionality of basic_istream<>::tellg and basic_ostream<>::tellp and the difference between them. tellg(): The function is defined in the istream class, and used with input streams. It returns the position of the current character in the input strea
2 min read
Relationship Between Pointer and Array in C In C programming language, pointers and arrays are closely related. An array name acts like a pointer constant. The value of this pointer constant is the address of the first element. If we assign this value to a non-constant pointer of the same type, then we can access the elements of the array usi
6 min read
What does main() return in C and C++? C According to coding standards, a good return program must exit the main function with 0. Although we are using void main() in C, In which we have not suppose to write any kind of return statement but that doesn't mean that C code doesn't require 0 as exit code. Let's see one example to clear our t
3 min read