signed, unsigned, short, long în C++

Tipuri de date C++98 (long long: C++11)

Modificatori care schimbă mărimea (short, long) sau semnul (signed, unsigned) tipurilor întregi.

Sintaxă
short s;            // cel puțin 16 biți
long l;             // cel puțin 32 de biți
long long ll;       // cel puțin 64 de biți
unsigned int u;     // fără semn: doar valori >= 0
signed char sc;     // char cu semn

Ce face signed, unsigned, short, long

short și long schimbă mărimea unui întreg: short are cel puțin 16 biți, long cel puțin 32, long long cel puțin 64. Mărimea exactă depinde de sistem: long are 8 octeți pe Linux și macOS pe 64 de biți, dar doar 4 pe Windows. Dacă ai nevoie de o mărime exactă, folosește std::int64_t și tipurile din <cstdint>.

unsigned face ca tipul să nu aibă semn: nu poate ține valori negative, dar poate ține valori pozitive de două ori mai mari. signed este implicit pentru int, short și long, deci se scrie de obicei doar la signed char.

Calculele cu unsigned nu depășesc niciodată limita: rezultatul „se întoarce” (0 – 1 devine valoarea maximă). Comportamentul este bine definit, dar sursă frecventă de greșeli.

Exemple

Exemplul 1: Mărimile tipurilor întregi

Rezultatul este de pe macOS pe 64 de biți (Apple M). Pe Windows, long ar avea 4 octeți.

#include <print>

int main() {
    std::println("short: {} octeți", sizeof(short));
    std::println("int: {} octeți", sizeof(int));
    std::println("long: {} octeți", sizeof(long));
    std::println("long long: {} octeți", sizeof(long long));
    std::println("unsigned int: {} octeți", sizeof(unsigned int));
}

Rezultat

short: 2 octeți
int: 4 octeți
long: 8 octeți
long long: 8 octeți
unsigned int: 4 octeți

Exemplul 2: Limitele cu și fără semn

#include <limits>
#include <print>

int main() {
    std::println("short:          {} ... {}", std::numeric_limits<short>::min(), std::numeric_limits<short>::max());
    std::println("unsigned short: {} ... {}", std::numeric_limits<unsigned short>::min(), std::numeric_limits<unsigned short>::max());
    std::println("long long:      {} ... {}", std::numeric_limits<long long>::min(), std::numeric_limits<long long>::max());
    std::println("unsigned int:   {} ... {}", std::numeric_limits<unsigned int>::min(), std::numeric_limits<unsigned int>::max());
}

Rezultat

short:          -32768 ... 32767
unsigned short: 0 ... 65535
long long:      -9223372036854775808 ... 9223372036854775807
unsigned int:   0 ... 4294967295

Exemplul 3: Întoarcerea valorilor fără semn

Scăzând 1 din 0 într-un unsigned int, rezultatul devine cea mai mare valoare posibilă. Adunând 1 la maxim, revine la 0.

#include <print>

int main() {
    unsigned int stoc = 0;
    stoc = stoc - 1;
    std::println("0 - 1 = {}", stoc);
    stoc = stoc + 1;
    std::println("înapoi la {}", stoc);
    long long populatie_lume = 8'100'000'000;
    std::println("Populația lumii: {}", populatie_lume);
}

Rezultat

0 - 1 = 4294967295
înapoi la 0
Populația lumii: 8100000000

Greșeli frecvente

  • Compari un număr cu semn cu unul fără semn: -1 < 0u este false, pentru că -1 este transformat într-un unsigned uriaș. Compilatorul avertizează (-Wsign-compare); folosește std::cmp_less sau același tip în ambele părți.
  • Scrii o buclă descrescătoare cu unsigned: for (unsigned i = n - 1; i >= 0; --i). Condiția este mereu adevărată (un unsigned nu e niciodată negativ), deci bucla nu se oprește.
  • Presupui că long are 8 octeți. Pe Windows are 4, deci programul care merge pe Linux dă rezultate greșite. Pentru 64 de biți garantat folosește long long sau std::int64_t.

Comenzi înrudite

  • int: Tipul de bază pentru numere întregi (fără zecimale), de obicei pe 4 octeți, cu valori între aproximativ -2,1 și 2,1 miliarde.
  • char: Tipul pentru un singur caracter (un octet); în spate este un număr mic, codul caracterului.
  • sizeof: Dă numărul de octeți ocupați în memorie de un tip sau de o variabilă; se calculează la compilare.
  • double, float: Tipuri pentru numere reale (cu zecimale): double are aproximativ 15-16 cifre exacte, float doar 6-7.
  • std::numeric_limits: Dă proprietățile unui tip numeric: valoarea maximă și minimă, precizia, dacă are semn, infinitul.
  • std::size_t: Tip întreg fără semn pentru mărimi și indici: îl returnează sizeof și metodele size() ale containerelor.
  • std::int32_t: Tipuri întregi cu mărime exactă: int32_t are mereu 32 de biți, uint8_t 8 biți fără semn etc.