Question: I have the below simple program:

```
#include <iostream>
#include <stdio.h>

void SomeFunction(int a)
{
  std::cout<<"Value in function: a = "<<a<<std::endl;
}

int main(){

  size_t a(0);

  std::cout<<"Value in main: "<<a-1<<std::endl;
  SomeFunction(a-1);

  return 0;

}

```

Upon executing this I get:

> 
> Value in main: 18446744073709551615
> 
> 
> Value in function: a = -1
> 
> 
> 

I think I roughly understand why the function gets the 'correct' value of -1: there is an implicit conversion from the unsigned type to the signed one i.e. 18446744073709551615(unsigned) = -1(signed).

Is there any situation where the function will not get the 'correct' value?

Answer: 
Not on your computer... but technically yes, there is a situation where things can go wrong.

All modern PCs use the "two's complement" system for signed integer arithmetic (read Wikipedia for details). Two's complement has many advantages, but one of the biggest is this: *unsaturated addition and subtraction of signed integers is identical to that of unsigned integers*. As long as overflow/underflow causes the result to "wrap around" (i.e., 0-1 = UINT\_MAX), the computer can add and subtract without even knowing whether you're interpreting the numbers as signed or unsigned.

BUT! C/C++ do not technically *require* two's complement for signed integers. There are two other permissible systems, known as "sign-magnitude" and "one's complement". These are unusual systems, never found outside antique architectures and embedded processors (and rarely even there). But in those systems, signed and unsigned arithmetic do not match up, and `(signed)(a+b)` will not necessarily equal `(signed)a + (signed) b`.

There's another, more mundane caveat when you're also narrowing types, as is the case between `size_t` and `int` on x64, because C/C++ don't require compilers to follow a particular rule when narrowing out-of-range values to signed types. This is likewise more a matter of language lawyering than actual unsafeness, though: VC++, GCC, Clang, and all other compilers I'm aware of narrow through truncation, leading to the expected behavior.
It's easier to compare and contrast `signed` and `insigned` of type same basic type, say `signed int` and `unsigned int`.

On a system that uses 32 bits for `int`, the range of `unsigned int` is [`0` - `4294967295`] and the range of `signed int` is [`-2147483647` - `2147483647`].

Say you have a variable of type `unsigned int` and its value is greater than `2147483647`. If you pass such a variable to `SomeFunction`, you will see an incorrect value in the function.

Conversely, say you have a variable of type `signed int` and its value is less than zero. If you pass such a variable to a function that expects an `unsigned int`, you will see an incorrect value in the function.