Ce face ckd_add, ckd_sub, ckd_mul
Dacă rezultatul unei operații cu int nu încape în tip (de exemplu INT_MAX + 1), C nu dă eroare: este comportament nedefinit, iar programul poate face orice. Verificarea manuală înainte de operație este ușor de greșit.
Antetul C23 <stdckdint.h> are trei macro: ckd_add, ckd_sub și ckd_mul. Primul argument este adresa unde se pune rezultatul. Valoarea returnată este false dacă rezultatul matematic a încăput în tipul destinației și true dacă a fost depășire. La depășire, în destinație ajunge rezultatul „trunchiat” (ca la tipurile fără semn), dar nu se produce comportament nedefinit.
Tipurile argumentelor pot fi diferite; contează tipul destinației. Funcțiile merg cu orice tip întreg, în afară de bool, char simplu și enum.
Parametri
| Parametru | Descriere |
|---|---|
rezultat |
Pointer la variabila în care se scrie rezultatul (tipul ei decide dacă rezultatul „încape”). |
a, b |
Operanzii, de orice tip întreg. |
Ce returnează
false dacă rezultatul exact a încăput în *rezultat, true dacă a fost depășire.
Exemple
Exemplul 1: Adunare care depășește INT_MAX
Prima adunare încape, a doua nu. Programul află asta din valoarea returnată, fără comportament nedefinit.
#include <limits.h>
#include <stdckdint.h>
#include <stdio.h>
int main(void) {
int total;
if (!ckd_add(&total, 2000000000, 100000000)) {
printf("Total: %d\n", total);
}
if (ckd_add(&total, INT_MAX, 1)) {
printf("Depășire: INT_MAX + 1 nu încape într-un int\n");
}
return 0;
}
Rezultat
Total: 2100000000
Depășire: INT_MAX + 1 nu încape într-un int
Exemplul 2: Calculul sigur al memoriei pentru malloc
Înainte de malloc(n * dimensiune), produsul trebuie verificat: dacă depășește, s-ar cere mult mai puțină memorie decât crezi. Aici destinația este size_t.
#include <stdckdint.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
static void *aloca_tablou(size_t n, size_t dimensiune) {
size_t total;
if (ckd_mul(&total, n, dimensiune)) {
printf("Cerere prea mare: %zu x %zu octeți\n", n, dimensiune);
return nullptr;
}
printf("Aloc %zu octeți\n", total);
return malloc(total);
}
int main(void) {
double *preturi = aloca_tablou(1000, sizeof(double));
void *urias = aloca_tablou(SIZE_MAX / 2, 4);
free(preturi);
free(urias);
return 0;
}
Rezultat
Aloc 8000 octeți
Cerere prea mare: 9223372036854775807 x 4 octeți
Exemplul 3: Destinație de alt tip decât operanzii
Operanzii sunt int, dar destinația este unsigned char (0–255). 200 + 50 încape, 200 + 100 nu; la depășire, în destinație ajunge 300 modulo 256 = 44. La scădere, -5 nu încape într-un tip fără semn.
#include <stdckdint.h>
#include <stdio.h>
int main(void) {
unsigned char luminozitate;
bool depasire;
depasire = ckd_add(&luminozitate, 200, 50);
printf("200 + 50 -> %3d, depășire: %s\n", luminozitate, depasire ? "da" : "nu");
depasire = ckd_add(&luminozitate, 200, 100);
printf("200 + 100 -> %3d, depășire: %s\n", luminozitate, depasire ? "da" : "nu");
unsigned int stoc;
depasire = ckd_sub(&stoc, 10, 15);
printf("10 - 15 într-un unsigned: depășire: %s\n", depasire ? "da" : "nu");
return 0;
}
Rezultat
200 + 50 -> 250, depășire: nu
200 + 100 -> 44, depășire: da
10 - 15 într-un unsigned: depășire: da
Greșeli frecvente
- Ignori valoarea returnată și folosești direct rezultatul. Rolul funcțiilor este tocmai verificarea; la depășire, rezultatul din destinație nu este cel matematic.
- Dai ca prim argument variabila, nu adresa ei:
ckd_add(total, a, b). Este nevoie de&total. - Folosești
<stdckdint.h>cu un compilator vechi. Antetul există în GCC 14+ și Clang 18+; altfel, GCC și Clang au funcțiile echivalente__builtin_add_overflowși înrudite.
Comenzi înrudite
stdint.h și limits.h: Tipuri întregi cu dimensiune exactă (int32_t, uint8_t) și constantele cu valorile minime și maxime ale tipurilor (INT_MAX).Operatori aritmetici (+ - * / % ++ --): Adunare, scădere, înmulțire, împărțire, restul împărțirii, atribuiri compuse și incrementare cu ++ / –.Comportament nedefinit (undefined behavior): Situațiile pentru care standardul C nu spune ce se întâmplă: programul poate merge, poate da rezultate greșite sau se poate opri.malloc: Cere sistemului un bloc de memorie de mărimea dată, în timpul rulării, și returnează adresa lui sau NULL dacă nu reușește.bool, true, false: Tipul pentru valori adevărat/fals. În C23, bool, true și false sunt cuvinte cheie, fără să mai incluzi stdbool.h.
Întrebări & Exemple de Cod:
ckd_add, ckd_sub, ckd_mulAi o nelămurire despre utilizarea comenzii
ckd_add, ckd_sub, ckd_mulsau ai descoperit un truc / fragment de cod util? Distribuie-l cu ceilalți programatori!Fii primul care pune o întrebare sau distribuie un fragment de cod / prompt!
Nu au fost adăugate încă întrebări sau exemple de cod pentru această pagină. Dacă ai întâlnit o problemă sau ai un snippet util, adaugă-l mai jos pentru a-i ajuta pe ceilalți.