Tipos de dados C - C data types

Na linguagem de programação C , os tipos de dados constituem a semântica e as características de armazenamento dos elementos de dados. Eles são expressos na sintaxe da linguagem na forma de declarações para localizações ou variáveis ​​de memória . Os tipos de dados também determinam os tipos de operações ou métodos de processamento de elementos de dados.

A linguagem C fornece tipos aritméticos básicos, como tipos de número inteiro e real , e sintaxe para construir tipos de array e compostos. Os cabeçalhos da biblioteca padrão C , a serem usados ​​por meio de diretivas de inclusão , contêm definições de tipos de suporte, que possuem propriedades adicionais, como fornecer armazenamento com um tamanho exato, independente da implementação da linguagem em plataformas de hardware específicas.

Tipos básicos

Tipos principais

A linguagem C fornece os quatro especificadores básicos de tipo aritmético char , int , float e double , e os modificadores signed , unsigned , short e long . A tabela a seguir lista as combinações permitidas na especificação de um grande conjunto de declarações específicas de tamanho de armazenamento.

Modelo Explicação Tamanho mínimo (bits) Especificador de formato
char A menor unidade endereçável da máquina que pode conter conjunto de caracteres básicos. É um tipo inteiro . O tipo real pode ser assinado ou não. Ele contém CHAR_BIT bits. 8 %c
signed char Do mesmo tamanho que char , mas com garantia de assinatura. Capaz de conter pelo menos o intervalo [−127, +127]. 8 %c (ou %hhipara saída numérica)
unsigned char Do mesmo tamanho que char , mas garantidamente sem sinal. Contém pelo menos o intervalo [0, 255]. 8 %c (ou %hhupara saída numérica)
short
short int
signed short
signed short int
Tipo inteiro curto com sinal. Capaz de conter pelo menos o intervalo [-32.767, +32.767]. 16 %hi ou %hd
unsigned short
unsigned short int
Tipo inteiro curto sem sinal. Contém pelo menos o intervalo [0, 65.535]. 16 %hu
int
signed
signed int
Tipo de inteiro com sinal básico. Capaz de conter pelo menos o intervalo [-32.767, +32.767]. 16 %i ou %d
unsigned
unsigned int
Tipo de inteiro sem sinal básico. Contém pelo menos o intervalo [0, 65.535]. 16 %u
long
long int
signed long
signed long int
Tipo inteiro com sinal longo . Capaz de conter pelo menos o intervalo [-2.147.483.647, +2.147.483.647]. 32 %li ou %ld
unsigned long
unsigned long int
Tipo inteiro longo sem sinal. Capaz de conter pelo menos a faixa [0, 4.294.967.295]. 32 %lu
long long
long long int
signed long long
signed long long int
Tipo inteiro longo com sinal. Capaz de conter pelo menos a faixa [-9.223.372.036.854.775.807, +9.223.372.036.854.775.807]. Especificado desde a versão C99 do padrão. 64 %lli ou %lld
unsigned long long
unsigned long long int
Tipo inteiro não assinado longo longo . Contém pelo menos a faixa [0, +18.446.744.073.709.551.615]. Especificado desde a versão C99 do padrão. 64 %llu
float Tipo de ponto flutuante real, geralmente referido como tipo de ponto flutuante de precisão única. Propriedades reais não especificadas (exceto limites mínimos); entretanto, na maioria dos sistemas, esse é o formato de ponto flutuante binário de precisão única IEEE 754 (32 bits). Este formato é exigido pelo anexo F opcional "Aritmética de ponto flutuante IEC 60559". Convertendo de texto:
double Tipo de ponto flutuante real, geralmente conhecido como tipo de ponto flutuante de precisão dupla. Propriedades reais não especificadas (exceto limites mínimos); entretanto, na maioria dos sistemas, este é o formato de ponto flutuante binário de precisão dupla IEEE 754 (64 bits). Este formato é exigido pelo anexo F opcional "IEC 60559 aritmética de ponto flutuante".
long double Tipo de ponto flutuante real, geralmente mapeado para um formato de número de ponto flutuante de precisão estendida . Propriedades reais não especificadas. Pode ser o formato de ponto flutuante de precisão estendida x86 (80 bits, mas normalmente 96 bits ou 128 bits na memória com bytes de preenchimento ), o não-IEEE " duplo-duplo " (128 bits), flutuante de precisão quádrupla IEEE 754 formato de ponto (128 bits) ou igual a double. Veja o artigo sobre long double para detalhes. %Lf %LF
%Lg %LG
%Le %LE
%La %LA

O tamanho real dos tipos inteiros varia de acordo com a implementação. O padrão requer apenas relações de tamanho entre os tipos de dados e tamanhos mínimos para cada tipo de dados:

Os requisitos de relação são que long longnão seja menor que long, que não seja menor que int, que não seja menor que short. Como charo tamanho de é sempre o tipo de dados mínimo suportado, nenhum outro tipo de dados (exceto campos de bits ) pode ser menor.

O tamanho mínimo para charé de 8 bits, o tamanho mínimo para shorte inté de 16 bits, longpois é de 32 bits e long longdeve conter pelo menos 64 bits.

O tipo intdeve ser o tipo inteiro com o qual o processador de destino está trabalhando de forma mais eficiente. Isso permite grande flexibilidade: por exemplo, todos os tipos podem ser de 64 bits. No entanto, vários esquemas de largura inteira diferentes (modelos de dados) são populares. Como o modelo de dados define como diferentes programas se comunicam, um modelo de dados uniforme é usado em uma determinada interface de aplicativo do sistema operacional.

Na prática, chargeralmente tem 8 bits de tamanho e short16 bits (assim como seus equivalentes não assinados). Isso vale para plataformas tão diversas como SunOS  4 Unix dos anos 1990 , Microsoft MS-DOS , Linux moderno e Microchip MCC18 para microcontroladores PIC de 8 bits incorporados . POSIX precisa charter exatamente 8 bits de tamanho.

Várias regras no padrão C tornam unsigned charo tipo básico usado para arrays adequado para armazenar objetos arbitrários que não sejam de campo de bits: sua falta de bits de preenchimento e representações de trap, a definição de representação de objeto e a possibilidade de aliasing.

O tamanho real e o comportamento dos tipos de ponto flutuante também variam de acordo com a implementação. A única garantia é que long doublenão seja menor que double, que não seja menor que float. Normalmente, são usados ​​os formatos de ponto flutuante binário IEEE 754 de 32 e 64 bits .

O padrão C99 inclui novos tipos de ponto flutuante real float_te double_t, definido em <math.h>. Eles correspondem aos tipos usados ​​para os resultados intermediários de expressões de ponto flutuante quando FLT_EVAL_METHODé 0, 1 ou 2. Esses tipos podem ser mais largos que long double.

C99 também acrescentou complexos tipos: float _Complex, double _Complex, long double _Complex.

Tipo booleano

C99 adicionou um tipo booleano (verdadeiro / falso) _Bool. Além disso, o <stdbool.h>cabeçalho é definido boolcomo um alias conveniente para esse tipo e também fornece macros para truee false. _Boolfunções de forma semelhante a um tipo inteiro normal, com uma exceção: quaisquer atribuições a a _Boolque não sejam 0 (falso) são armazenadas como 1 (verdadeiro). Esse comportamento existe para evitar estouros de inteiros em conversões de estreitamento implícitas. Por exemplo, no seguinte código:

unsigned char b = 256;

if (b) {
	/* do something */
}

A variável é bavaliada como falsa se unsigned chartiver um tamanho de 8 bits. Isso ocorre porque o valor 256 não se ajusta ao tipo de dados, o que resulta na utilização dos 8 bits inferiores dele, resultando em um valor zero. No entanto, alterar o tipo faz com que o código anterior se comporte normalmente:

_Bool b = 256;

if (b) {
	/* do something */
}

O tipo _Bool também garante que os valores verdadeiros sempre sejam comparados iguais entre si:

_Bool a = 1, b = 2;

if (a == b) {
	/* do something */
}

Tipos de diferença de tamanho e ponteiro

A especificação de linguagem C inclui o typedef s size_te ptrdiff_tpara representar quantidades de memória-relacionado. Seu tamanho é definido de acordo com os recursos aritméticos do processador de destino, não os recursos de memória, como espaço de endereço disponível. Ambos os tipos são definidos no <stddef.h>cabeçalho ( cstddefem C ++).

size_té um tipo inteiro sem sinal usado para representar o tamanho de qualquer objeto (incluindo matrizes) na implementação específica. O operador sizeof produz um valor do tipo size_t. O tamanho máximo de size_té fornecido por meio de SIZE_MAXuma constante de macro que é definida no cabeçalho ( cabeçalho em C ++). tem a garantia de ter pelo menos 16 bits de largura. Além disso, POSIX inclui , que é um tipo inteiro assinado da mesma largura que . <stdint.h>cstdintsize_tssize_tsize_t

ptrdiff_té um tipo inteiro assinado usado para representar a diferença entre os ponteiros. É garantido que seja válido apenas contra ponteiros do mesmo tipo; a subtração de ponteiros consistindo em diferentes tipos é definida pela implementação.

Interface para as propriedades dos tipos básicos

Informações sobre as propriedades reais, como tamanho, dos tipos aritméticos básicos, são fornecidas por meio de constantes de macro em dois cabeçalhos: <limits.h>cabeçalho ( climitscabeçalho em C ++) define macros para tipos inteiros e <float.h>cabeçalho ( cfloatcabeçalho em C ++) define macros para tipos de ponto flutuante . Os valores reais dependem da implementação.

Propriedades de tipos inteiros

  • CHAR_BIT - tamanho do tipo char em bits (pelo menos 8 bits)
  • SCHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN(C99) - valor mínimo possível de tipos assinados inteiros: char assinado, assinado short, int assinado, assinado longa, assinado longa, longa
  • SCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX(C99) - valor máximo possível de tipos assinados inteiros: char assinado, assinado short, int assinado, assinado longa, assinado longa, longa
  • UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX, ULLONG_MAX(C99) - valor máximo possível de tipos inteiro sem sinal: unsigned char não assinado, curto, unsigned int, sem assinatura longo, sem assinatura de comprimento longo
  • CHAR_MIN - valor mínimo possível de char
  • CHAR_MAX - valor máximo possível de char
  • MB_LEN_MAX - número máximo de bytes em um caractere multibyte

Propriedades de tipos de ponto flutuante

  • FLT_MIN, DBL_MIN, LDBL_MIN- mínimo normalizado valor positivo de float, double, long double, respectivamente
  • FLT_TRUE_MIN, DBL_TRUE_MIN, LDBL_TRUE_MIN(C11) - valor mínimo positivo de flutuador, duas vezes, respectivamente longo duplo
  • FLT_MAX, DBL_MAX, LDBL_MAX- valor finito máximo de float, double, long double, respectivamente
  • FLT_ROUNDS - modo de arredondamento para operações de ponto flutuante
  • FLT_EVAL_METHOD (C99) - método de avaliação de expressões envolvendo diferentes tipos de ponto flutuante
  • FLT_RADIX - raiz do expoente nos tipos de ponto flutuante
  • FLT_DIG, DBL_DIG, LDBL_DIG- número de dígitos decimais que podem ser representados sem perder precisão, float, double, long double, respectivamente
  • FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON- diferença entre 1,0 e o valor seguinte representável de flutuador, duas vezes, a longo duplo, respectivamente
  • FLT_MANT_DIG, DBL_MANT_DIG, LDBL_MANT_DIG- número de FLT_RADIXdígitos -base no significand de ponto flutuante para tipos de flutuar, duas vezes, a longo duplo, respectivamente
  • FLT_MIN_EXP, DBL_MIN_EXP, LDBL_MIN_EXP- negativo mínimo número inteiro de tal modo que FLT_RADIXelevada a uma potência inferior a um número que é uma bóia normalizada, duas vezes, a longo duplo, respectivamente
  • FLT_MIN_10_EXP, DBL_MIN_10_EXP, LDBL_MIN_10_EXP- negativo mínimo número inteiro tal que 10 levantada para que a energia é uma bóia normalizada, duas vezes, a longo duplo, respectivamente
  • FLT_MAX_EXP, DBL_MAX_EXP, LDBL_MAX_EXP- positivo máximo número inteiro de tal modo que FLT_RADIXelevada a uma potência inferior a um número que é uma bóia normalizada, duas vezes, a longo duplo, respectivamente
  • FLT_MAX_10_EXP, DBL_MAX_10_EXP, LDBL_MAX_10_EXP- máximo positivo inteiro tal que 10 levantada para que a energia é uma bóia normalizada, duas vezes, a longo duplo, respectivamente
  • DECIMAL_DIG(C99) - número mínimo de dígitos decimais de forma que qualquer número do tipo de ponto flutuante mais amplo suportado possa ser representado em decimal com uma precisão de DECIMAL_DIGdígitos e lido de volta no tipo de ponto flutuante original sem alterar seu valor. DECIMAL_DIGé pelo menos 10.

Tipos inteiros de largura fixa

O padrão C99 inclui definições de vários novos tipos de inteiros para aprimorar a portabilidade dos programas. Os tipos inteiros básicos já disponíveis foram considerados insuficientes, porque seus tamanhos reais são definidos pela implementação e podem variar entre diferentes sistemas. Os novos tipos são especialmente úteis em ambientes embarcados onde o hardware geralmente suporta apenas vários tipos e esse suporte varia entre os diferentes ambientes. Todos os novos tipos são definidos no <inttypes.h>cabeçalho ( cinttypescabeçalho em C ++) e também estão disponíveis no <stdint.h>cabeçalho ( cstdintcabeçalho em C ++). Os tipos podem ser agrupados nas seguintes categorias:

  • Tipos inteiros de largura exata que têm a garantia de ter o mesmo número n de bits em todas as implementações. Incluído apenas se estiver disponível na implementação.
  • Tipos de número inteiro de menor largura que são garantidamente o menor tipo disponível na implementação, que tem pelo menos um número n especificado de bits. Garantido para ser especificado para pelo menos N = 8,16,32,64.
  • Tipos de número inteiro mais rápidos que são garantidos como o tipo de número inteiro mais rápido disponível na implementação, que tem pelo menos um número n especificado de bits. Garantido para ser especificado para pelo menos N = 8,16,32,64.
  • Tipos inteiros de ponteiro que têm a garantia de conter um ponteiro. Incluído apenas se estiver disponível na implementação.
  • Tipos de número inteiro de largura máxima que são garantidamente o maior tipo de número inteiro na implementação.

A tabela a seguir resume os tipos e a interface para adquirir os detalhes de implementação ( n se refere ao número de bits):

Categoria de tipo Tipos assinados Tipos sem sinal
Modelo Valor mínimo Valor máximo Modelo Valor mínimo Valor máximo
Largura exata intn_t INTn_MIN INTn_MAX uintn_t 0 UINTn_MAX
Menor largura int_leastn_t INT_LEASTn_MIN INT_LEASTn_MAX uint_leastn_t 0 UINT_LEASTn_MAX
O mais rápido int_fastn_t INT_FASTn_MIN INT_FASTn_MAX uint_fastn_t 0 UINT_FASTn_MAX
Pointer intptr_t INTPTR_MIN INTPTR_MAX uintptr_t 0 UINTPTR_MAX
Largura máxima intmax_t INTMAX_MIN INTMAX_MAX uintmax_t 0 UINTMAX_MAX

Especificadores de formato Printf e scanf

O <inttypes.h>cabeçalho ( cinttypesem C ++) fornece recursos que aprimoram a funcionalidade dos tipos definidos no <stdint.h>cabeçalho. Ele define macros para os especificadores de string de formato printf e string de formato scanf correspondentes aos tipos definidos em <stdint.h>e várias funções para trabalhar com os tipos intmax_te uintmax_t. Este cabeçalho foi adicionado em C99 .

String de formato Printf

As macros estão no formato . Aqui, {fmt} define a formatação de saída e é um de (decimal), (hexadecimal), (octal), (sem sinal) e (inteiro). {tipo} define o tipo do argumento e é um de , , , , , em que corresponde ao número de bits na argumento. PRI{fmt}{type}dxouinFASTnLEASTnPTRMAXn

String de formato Scanf

As macros estão no formato . Aqui, {fmt} define a formatação de saída e é um de (decimal), (hexadecimal), (octal), (sem sinal) e (inteiro). {tipo} define o tipo do argumento e é um de , , , , , em que corresponde ao número de bits na argumento. SCN{fmt}{type}dxouinFASTnLEASTnPTRMAXn

Funções

Tipos adicionais de ponto flutuante

Da mesma forma que os tipos inteiros de largura fixa, ISO / IEC TS 18661 especifica tipos de ponto flutuante para intercâmbio IEEE 754 e formatos estendidos em binário e decimal:

  • _FloatN para formatos de intercâmbio binários;
  • _DecimalN para formatos de intercâmbio decimal;
  • _FloatNx para formatos estendidos binários;
  • _DecimalNx para formatos estendidos decimais.

Estruturas

As estruturas agregam o armazenamento de vários itens de dados, de tipos de dados potencialmente diferentes, em um bloco de memória referenciado por uma única variável. O exemplo a seguir declara o tipo de dados struct birthdayque contém o nome e o aniversário de uma pessoa. A definição da estrutura é seguida por uma declaração da variável Johnque aloca o armazenamento necessário.

struct birthday {
	char name[20];
	int day;
	int month;
	int year;
};

struct birthday John;

O layout de memória de uma estrutura é um problema de implementação de linguagem para cada plataforma, com algumas restrições. O endereço de memória do primeiro membro deve ser igual ao endereço da própria estrutura. As estruturas podem ser inicializadas ou atribuídas usando literais compostos. Uma função pode retornar diretamente uma estrutura, embora isso geralmente não seja eficiente em tempo de execução. Desde C99 , uma estrutura também pode terminar com um membro de matriz flexível .

Uma estrutura que contém um ponteiro para uma estrutura de seu próprio tipo é comumente usada para construir estruturas de dados vinculadas :

struct node {
	int val;
	struct node *next;
};

Arrays

Para cada tipo T, exceto os tipos void e function, existem os tipos "array de Nelementos do tipo T" . Uma matriz é uma coleção de valores, todos do mesmo tipo, armazenados de forma contígua na memória. Uma matriz de tamanho Né indexada por inteiros de 0até e incluindo N−1. Aqui está um breve exemplo:

int cat[10];  // array of 10 elements, each of type int

Os arrays podem ser inicializados com um inicializador composto, mas não atribuídos. Os arrays são passados ​​para funções passando um ponteiro para o primeiro elemento. Matrizes multidimensionais são definidas como "matriz de matriz ..." e todas, exceto a dimensão mais externa, devem ter tamanho constante de tempo de compilação:

int a[10][8];  // array of 10 elements, each of type 'array of 8 int elements'

Ponteiros

Cada tipo de dados Ttem um ponteiro deT tipo correspondente para . Um ponteiro é um tipo de dados que contém o endereço de um local de armazenamento de uma variável de um tipo específico. Eles são declarados com o declarador de *tipo asterisk ( ) após o tipo de armazenamento básico e precedendo o nome da variável. Espaços em branco antes ou depois do asterisco são opcionais.

char *square;
long *circle;
int *oval;

Ponteiros também podem ser declarados para tipos de dados de ponteiro, criando assim vários ponteiros indiretos, como char ** e int *** , incluindo ponteiros para tipos de matriz. Os últimos são menos comuns do que uma matriz de ponteiros e sua sintaxe pode ser confusa:

char *pc[10];   // array of 10 elements of 'pointer to char'
char (*pa)[10]; // pointer to a 10-element array of char

O elemento pcrequer dez blocos de memória do tamanho de um ponteiro parachar (geralmente 40 ou 80 bytes em plataformas comuns), mas o elemento paé apenas um ponteiro (tamanho 4 ou 8 bytes) e os dados aos quais se refere são uma matriz de dez bytes ( ) sizeof *pa == 10

Sindicatos

Um tipo de união é uma construção especial que permite o acesso ao mesmo bloco de memória usando uma escolha de descrições de tipo diferentes. Por exemplo, uma união de tipos de dados pode ser declarada para permitir a leitura dos mesmos dados como um inteiro, um ponto flutuante ou qualquer outro tipo declarado pelo usuário:

union {
	int i;
	float f;
	struct {
		unsigned int u;
		double d;
	} s;
} u;

O tamanho total de ué o tamanho de u.s- que passa a ser a soma dos tamanhos de u.s.ue u.s.d- uma vez que sé maior do que ambos ie f. Ao atribuir algo a u.i, algumas partes de u.fpodem ser preservadas se u.iforem menores que u.f.

Ler de um membro do sindicato não é o mesmo que lançar uma vez que o valor do membro não é convertido, mas apenas lido.

Ponteiros de função

Os ponteiros de função permitem referenciar funções com uma assinatura específica. Por exemplo, para armazenar o endereço da função padrão absna variável my_int_f:

int (*my_int_f)(int) = &abs;
// the & operator can be omitted, but makes clear that the "address of" abs is used here

Os ponteiros de função são chamados por nome, exatamente como chamadas de função normais. Os ponteiros de função são separados dos ponteiros e ponteiros nulos .

Qualificadores de tipo

Os tipos acima mencionados podem ser caracterizados adicionalmente por qualificadores de tipo , resultando em um tipo qualificado . Em 2014 e C11 , existem quatro qualificadores de tipo no padrão C: const( C89 ), volatile( C89 ), restrict( C99 ) e _Atomic( C11 ) - o último tem um nome privado para evitar conflito com nomes de usuário, mas o nome mais comum atomicpode ser usado se o <stdatomic.h>cabeçalho estiver incluído. Destes, consté de longe o mais conhecido e o mais usado, aparecendo na biblioteca padrão e encontrado em qualquer uso significativo da linguagem C, que deve satisfazer a correção constante . Os outros qualificadores são usados ​​para programação de baixo nível e, embora amplamente usados ​​lá, raramente são usados ​​por programadores típicos.

Veja também

Referências