LINGUAGEM: Linguagem C - Capítulo 3 - Parte 3


Enumerações e Campos de Bits

Enumerações

Uma enumeração é uma extensão da linguagem C acrescentada pelo padrão ANSI. Uma enumeração é uma declaração de um novo tipo de dados que consiste em um conjunto de constantes inteiras que especficam todos os valores legais que uma variável desse tipo pode ter.

Enumerações são definidas de forma semelhante a estruturas; no entanto, utiliza-se a palavra-chave enum para assinalar o início de um tipo de enumeração.

FORMA GERAL:
enum identificador {
  Simbolo_1,
  Simbolo_2,
  ...
  Simbolo_n
 }  var_1, var_2, ..., var_n;

Em uma enumaração cada Simbolo_i representa um valor inteiro. Cada símbolo recebe um valor maior em uma unidade do precedente. Por default, o valor do primeiro símbolo é 0. No entanto, você pode especificar o valor de um ou mais símbolos usando um inicializador. O símbolos que aparecem após os inicializadores recebem valores maiores que o da inicialização precedente.

Exemplos

enum dt_wday { 
 Sunday   ,
 Monday   ,
 Tuesday  ,
 Wednsday ,
 Thursday ,
 Friday   ,
 Saturday 
};

enum dt_month{
 January  = 1 ,
 February  ,
 Mars      ,
 April     ,
 May       ,
 June      ,
 July      ,
 August    ,
 September ,
 October   ,
 November  ,
 December
};

Campos de Bits



Exemplo

struct {
  unsigned mday : 5;
  unsigned month: 4;
  unsigned year :22;
  unsigned isBCE: 1;
 } bitf;

Exemplo Completo

O programa abaixo ilustra todos os mecanismos de definição de novos tipos estruturados pelo usuário:
  • estruturas struct
  • definição de novos nomes para tipos typedef
  • enumerações enum
  • uniões union
  • campos de bits struct
Além disso, o exemplo também aborda o uso de funções da biblioteca <time.h>.

Para o entedimento do exemplo que trata de datas do calendário gregoriano você pode consultar:
Para implementação do algoritmo DOOMSDAY para o cálculo do dia da semana de uma data, consulte:
/** date.h
    Author: Luciano R. Coutinho, 2007.
      lrc@deinf.ufma.br
*/
#ifndef DATE_H
#define DATE_H

#include <limits.h>

/* 
 * A type for storing dates in the range:
 * from  Jan 1st , year 2^22 BCE  
 * to    Dec 31th, year 2^22 
 */
#if ( UINT_MAX < 0xffffffff  )
typedef long   date_t;
#else
typedef int    date_t;
#endif

enum dt_wday { 
 Sunday   ,
 Monday   ,
 Tuesday  ,
 Wednsday ,
 Thursday ,
 Friday   ,
 Saturday 
};

enum dt_month{
 January  = 1 ,
 February  ,
 Mars      ,
 April     ,
 May       ,
 June      ,
 July      ,
 August    ,
 September ,
 October   ,
 November  ,
 December
};

struct dt {
    enum dt_wday    wday;   /* day of the week   : 0 .. 6     */
    unsigned        mday;   /* day of the month  : 1 .. 31    */
    unsigned        yday;   /* days since Jan. 1 : 1 .. 366   */
    unsigned        mweek;  /* week of the month : 0 .. 5     */
    unsigned        yweek;  /* week of the year  : 0 .. 53    */
    enum dt_month   month;  /* month          : 1 .. 12    */
    long            year;   /* year          : -2^22 .. 2^22  */
    unsigned        isBCE;  /* is Before Common Era ?         */
    long            serial; /* number of days                 */
};


date_t      date(date_t *);        /* get current date */
date_t      mkdate(struct dt *);   /* code   struct dt* in a date_t */
struct dt * gcdate(date_t);        /* decode date_t in a struct dt  */
struct dt * diffdate(date_t,date_t); /* interval between dates */

size_t      strfdate(char*, size_t, const char*, const struct dt*);

int     printf_date(const char *, const struct dt*);
int     scanf_date (const char *, const struct dt*);

#endif


/** date.c
    Author: Luciano R. Coutinho, 2007.
      lrc@deinf.ufma.br
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "date.h"


union date_t {
 date_t ival;
 struct {
  unsigned mday : 5;
  unsigned month: 4;
  unsigned year :22;
  unsigned isBCE: 1;
 } bitf;
};

/* Global Shared */

static       struct dt dt_buf;
static int   num_days[13] = { 
    0 , /* skiped */
    31, /* January  */
    28, /* February */
    31, /* Mars     */
    30, 
    31, 
    30, 
    31, 
    31, 
    30, 
    31, 
    30, 
    31  /* December */
};

/* Functions */

date_t date(date_t * d) {
    time_t           now = time(NULL);
    struct tm    *tm_now = localtime(&now);
    union date_t      ud;

    ud.bitf.mday = tm_now->tm_mday;
    ud.bitf.month= tm_now->tm_mon + 1;
    ud.bitf.year = tm_now->tm_year + 1900;
    ud.bitf.isBCE= 0;

    if ( d )
        *d = ud.ival;

    return ud.ival;
}

/*  Gregorian Calendar
   
    The Gregorian calendar system adopts the following leap year rule:

    * Every year that is exactly divisible by four is a leap year, except for years 
    that are exactly divisible by 100; the centurial years that are exactly 
    divisible by 400 are still leap years. For example, the year 1900 is not a leap 
    year; the year 2000 is a leap year.

    Doomsday Algorithm
    * It takes advantage of the fact that within any calendar year, some days (e.g., 3/1, 4/4, 6/6, 8/8, 10/10, 12/12, the last day of February) always occur on the same day of week - the so-called "doomsday".

 DOOMSDAY(y) = (Tuesday + (y) + (y)/4 - (y)/100 + (y)/400)%7
*/


static enum dt_wday  calculate_wday(union date_t ud) {

}

static short  gc_calculate_yday(union date_t ud) {
}

static short  gc_calculate_mweek(union date_t ud) {
}

static short  gc_calculate_yweek(union date_t ud) {
}

static long   gc_calculate_serial(union date_t ud) {
}

/** interprets a given date_t as a Gregorian calendar date */
struct dt * gcdate(date_t d) {
    union date_t ud = { d };

    dt_buf.mday = ud.bitf.mday ;
    dt_buf.month= ud.bitf.month;
    dt_buf.year = ud.bitf.year ;
    dt_buf.isBCE= ud.bitf.isBCE;

    gc_calculate_wday  ();
    gc_calculate_yday  ();
    gc_calculate_mweek ();
    gc_calculate_yweek ();
    gc_calculate_serial();
    
    return &dt_buf;
}


date_t mkdate(struct dt * sd) {

}


#include <stdio.h>
#include <stdlib.h>
#include "date.h"

union date_t {
 date_t ival;
 struct {
  unsigned mday : 5;
  unsigned month: 4;
  unsigned year :22;
  unsigned isBCE: 1;
 } bitf;
};

char  * wday_name[] = { "Seguinda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado" }

int main(int argc, char *argv[])
{
    union date_t ud;
    date_t      d;
    struct dt *sd;
 
    d = date(NULL);
  
    printf("hoje representado no tipo date_t: %ld\n",d);
    
    sd = gcdate(d);
    printf("hoje decomposto\t\t\t: %d %2d/%2d/%4d\n",sd->wday,sd->mday,sd->month,sd->year);

    ud.bitf.mday = 7;
    ud.bitf.month = September;
    ud.bitf.year    = 1822;
    ud.bitf.isBCE = 0;

    sd = gcdate(ud.ival);
    printf("a idependência ocorreu num(a) %s  \n",wday_name[sd->wday]);


    //system("PAUSE"); 

    return 0;
}

Exercícios

  1. Conclua o exemplo date.h/date.c; Escreva as funções
    • date_t mkdate(struct dt *); /* code struct dt* in a date_t */
    • struct dt * gcdate(date_t); /* decode date_t in a struct dt */
    • struct dt * diffdate(date_t,date_t); /* interval between dates */
    • size_t strfdate(char*, size_t, const char*, const struct dt*);
    • int printf_date(const char *, const struct dt*);
    • int scanf_date (const char *, const struct dt*);
  2. Escreva um programa que teste todas as funções criadas acima.

Bibliografia e fonte:

  • [CCT] Schildt, H. (1996) C, completo e total: 3a Ed.. São Paulo, Makron.
  • LP, UFMA; Coutinho, Lucian. Linguagem de programação para ciencia da computação da ufma.http://www.deinf.ufma.br/~lrc/2009.1/LP/
  • [K&R] KERNIGHAN, B. e RITCHIE, D. (1990) C, a linguagem de programação: padrão ANSI. Rio de Janeiro: Campus.
  • DEITEL, H. M. (1999) Como programar em C. Rio de Janeiro: LTC.
  • Módulo Consultoria e Informática (1989) Linguagem C: programação e aplicações. Rio de Janeiro: LTC.