Desafio C
Portabilidade com stdint.h e conversões seguras
Enunciado
Escreva um programa que use stdint.h para declarar variáveis de largura fixa: int8_t, uint16_t, int32_t e uint64_t. Atribua valores que exercitem os limites de cada tipo (por exemplo, INT8_MAX, UINT16_MAX, etc.). Imprima os valores e seus tamanhos com sizeof. Use os macros de limite de stdint.h para verificar se os valores estão dentro do intervalo antes de atribuir.
Requisitos
- Incluir
<stdint.h>e<stdio.h>. - Declarar as quatro variáveis com os tipos de largura fixa.
- Usar macros como
INT8_MAX,UINT16_MAX,INT32_MAX,UINT64_MAXpara inicializar ou verificar. - Imprimir cada valor e seu tamanho com
sizeof.
Código inicial
#include <stdio.h>
#include <stdint.h>
int main(void) {
// Declare e inicialize as variáveis
// Imprima valores e tamanhos
return 0;
}
Saída esperada
int8_t: 127 (1 byte)
uint16_t: 65535 (2 bytes)
int32_t: 2147483647 (4 bytes)
uint64_t: 18446744073709551615 (8 bytes)
Ver dica
Use PRId8, PRIu16, PRId32 e PRIu64 de <inttypes.h> para imprimir corretamente. Ou faça cast para tipos maiores.
Mostrar solução
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h> // para macros de formato
int main(void) {
// Tipos de largura fixa com valores máximos
int8_t i8 = INT8_MAX; // 127
uint16_t u16 = UINT16_MAX; // 65535
int32_t i32 = INT32_MAX; // 2147483647
uint64_t u64 = UINT64_MAX; // 18446744073709551615
// Impressão usando macros de formato para cada tipo
printf("int8_t: %" PRId8 " (%zu byte)\n", i8, sizeof(i8));
printf("uint16_t: %" PRIu16 " (%zu bytes)\n", u16, sizeof(u16));
printf("int32_t: %" PRId32 " (%zu bytes)\n", i32, sizeof(i32));
printf("uint64_t: %" PRIu64 " (%zu bytes)\n", u64, sizeof(u64));
// Verificação de intervalo antes de atribuir
int64_t valor = 300;
if (valor >= INT8_MIN && valor <= INT8_MAX) {
int8_t seguro = (int8_t)valor;
printf("Valor %" PRId64 " cabe em int8_t: %" PRId8 "\n", valor, seguro);
} else {
printf("Valor %" PRId64 " não cabe em int8_t\n", valor);
}
return 0;
}
Passo a passo
- Incluímos
<stdint.h>para os tipos de largura fixa e<inttypes.h>para os macros de formato (PRId8, etc.). - Declaramos
int8_t i8 = INT8_MAX;—INT8_MAXé 127, o maior valor positivo de 8 bits com sinal. uint16_t u16 = UINT16_MAX;— 65535, maior valor de 16 bits sem sinal.int32_t i32 = INT32_MAX;— 2147483647, maior valor de 32 bits com sinal.uint64_t u64 = UINT64_MAX;— 18446744073709551615, maior valor de 64 bits sem sinal.- Usamos
printfcom strings de formato concatenadas:"%" PRId8expande para"%hhd"ou similar, garantindo o tipo correto. sizeofretorna o tamanho em bytes, impresso com%zu.- Depois, mostramos uma verificação de intervalo usando
INT8_MINeINT8_MAXantes de converter umint64_tparaint8_t.
Por que funciona
stdint.h define tipos com largura exata (ex.: int8_t sempre 8 bits) independentemente da plataforma. Isso evita surpresas ao portar código. Os macros INT8_MAX, UINT16_MAX, etc., fornecem os limites de cada tipo. inttypes.h define macros de formato (como PRId8) que se expandem para o especificador correto (ex.: %hhd), garantindo impressão portável. A verificação de intervalo previne overflow em conversões.
Erros comuns
- Usar
%dparaint8_t:printf("%d", i8);— pode funcionar por promoção, mas o correto é%hhdouPRId8. - Atribuir valor fora do intervalo:
int8_t x = 200;— overflow, comportamento indefinido. - Esquecer de incluir
<inttypes.h>: os macrosPRId8não estarão definidos. - Usar
%luparauint64_t: em algumas plataformasunsigned longnão é 64 bits; usePRIu64.
Outra forma de resolver
Poderia usar long long e unsigned long long em vez de stdint.h, mas isso não garante largura fixa em todas as plataformas. stdint.h é a forma recomendada para código portável.
Saída esperada
int8_t: 127 (1 byte)
uint16_t: 65535 (2 bytes)
int32_t: 2147483647 (4 bytes)
uint64_t: 18446744073709551615 (8 bytes)
Valor 300 não cabe em int8_t