Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The - operator in C++ is a built-in token that functions as both a unary arithmetic operator for numeric negation and a binary arithmetic operator for subtraction and pointer arithmetic. Its behavior is strictly determined by the arity (number of operands) and the type of its operands.

Unary Minus

The unary - operator computes the arithmetic negation of its single right-hand operand. For integral types (including bool) and unscoped enumeration types, the operand undergoes integral promotion before the operation is applied. When applied to a bool, the operand is promoted to int (true becomes 1, false becomes 0), and the negation yields -1 or 0 of type int. For signed integer types, the operator returns the negated value. Because of integral promotion, applying the unary - operator to the minimum representable value of a narrow signed type (like signed char or short) safely promotes the value to int before negation, avoiding overflow (e.g., -SCHAR_MIN promotes to int(-128) and negates to int(128)). However, applying the unary - operator to the minimum representable value of a signed integer type with a conversion rank greater than or equal to int (such as int, long, or long long) results in signed integer overflow, which invokes Undefined Behavior (UB). For unsigned integer types, the behavior depends on the resulting type after integral promotion. If the operand promotes to a signed type (e.g., an unsigned char or unsigned short promoting to a signed int), standard signed negation is applied. If the promoted type remains unsigned (e.g., unsigned int or unsigned long), the result is computed using modulo arithmetic: the promoted value is subtracted from the maximum representable value of the promoted unsigned type plus one, effectively utilizing two’s complement wrap-around semantics. For floating-point types, no integral promotion occurs. The operator negates the value by flipping the sign bit, producing the additive inverse. This includes the capability of producing -0.0 according to IEEE 754 semantics.
// Syntax
-expression
// Example
int x = 5;
int y = -x; 
int b = -true; // 'true' promotes to 1, resulting in -1
double z = -0.0;

unsigned char uc = 5;
auto res = -uc; // 'uc' promotes to signed 'int', 'res' is -5 of type 'int'

Binary Minus

The binary - operator computes the difference between its left-hand operand (lhs) and right-hand operand (rhs). Syntactically, it groups with left-to-right associativity (i.e., a - b - c parses as (a - b) - c). However, the actual evaluation order of the lhs and rhs operands is unsequenced in C++; the compiler may evaluate either operand first. When applied to numeric types, the compiler applies the usual arithmetic conversions to bring both operands to a common type before performing the subtraction.
// Syntax
lhs - rhs
// Example
double a = 10.5;
int b = 3;
double c = a - b; // 'b' is implicitly converted to double before subtraction

Pointer Arithmetic Semantics

When the binary - operator is used with pointers, it invokes specific pointer arithmetic rules rather than standard numeric subtraction:
  1. Pointer minus Integer: Subtracting an integral value N from a pointer yields a new pointer of the same type. Semantically, the resulting pointer points N array elements backward from the original pointer’s position. The resulting pointer must remain within the bounds of the same array object (or one past the end). If the arithmetic results in a pointer outside these bounds, it invokes Undefined Behavior (UB).
  2. Pointer minus Pointer: Subtracting two pointers yields the exact number of elements between them. The pointers may differ in cv-qualification (e.g., subtracting an int* from a const int* is valid), provided both point to elements within the same array object (or one past the end). The result is a signed integer of type std::ptrdiff_t defined in <cstddef>.
#include <cstddef>

void pointer_arithmetic_example() {
    int arr[5] = {10, 20, 30, 40, 50};
    int* ptr = &arr[4];

    // Pointer minus integer
    // Valid: ptr - 3 points to arr[1], which is 3 elements backward
    int* new_ptr = ptr - 3; 

    // Pointer minus pointer
    // Valid: differing cv-qualifiers, but same array
    const int* cptr = &arr[4];
    std::ptrdiff_t distance = cptr - new_ptr; // Yields 3
}

Operator Overloading

The - operator can be overloaded for user-defined types (classes, structs, or enumerations). It can be implemented as either a member function or a non-member (friend/free) function. For binary overloads, non-member functions are generally preferred to allow implicit type conversions on the left-hand operand. To prevent ambiguous overload compilation errors, a type must declare either the member or the non-member binary overload, but not both for the exact same parameter types.
struct ComplexMember {
    // Unary minus overload (member function)
    ComplexMember operator-() const;

    // Binary minus overload (member function)
    ComplexMember operator-(const ComplexMember& rhs) const;
};

struct ComplexNonMember {
    // Unary minus overload (member function)
    ComplexNonMember operator-() const;
};

// Binary minus overload (non-member function)
// Mutually exclusive with a member binary operator- for the same types
ComplexNonMember operator-(const ComplexNonMember& lhs, const ComplexNonMember& rhs);
Master C++ with Deep Grasping Methodology!Learn More