====== Curso básico de C ====== ===== Estrutura de um programa ===== Um programa na linguagem C pode apresentar as mais diversas formas, até mesmo ser composto por uma única linha, pois o compilador de código atenta apenas ao cumprimento das regras de sintaxe e não exige a implementação de uma estrutura específica. Contudo, é aconselhável aos programadores, adotarem um estilo de programação que apresente clareza e simplicidade para qualquer tipo de pessoa que leia o código. Esta é a estrutura típica de um programa em linguagem C: /* Include header files */ #include #include /* Macro declarations */ #define PI 3.141 /* Data type definitions */ typedef struct { int a, b; } element; /* Global variables */ element e; /* Functions */ int main(void) { // Local variables int x; // Program code printf("Hello World!\n"); } ===== Comentários ===== Ao programador é dada a liberdade de escrever qualquer tipo de texto num ficheiro de código. Este texto é geralmente utilizado para escrever anotações ou descrição do funcionamento de um excerto de código, neste caso este texto é ignorado pelo compilador. Os comentários podem também ser utilizados para por exemplo excluir temporalmente bocados de código da compilação. Os dois tipos de métodos de comentários em linguagem C são: // Line comment is on one line. // Text after two slash signs is considered as comment. /* Block comment can be used to include more than one line. The beginning and the end of a comment is assigned with slash and asterisk signs. */ ===== Dados ===== ==== Tipos de dados ==== Os tipos básicos de dados do C: ^ Tipo ^ Valor Minimo ^ Valor Máximo ^ Bits ^ Bytes ^ | (signed) char | -128 | 127 | 8 | 1 | | unsigned char | 0 | 255 | 8 | 1 | | (signed) short | -32768 | 32767 | 16 | 2 | | unsigned short | 0 | 65535 | 16 | 2 | | (signed) long | -2147483648 | 2147483647 | 32 | 4 | | unsigned long | 0 | 4294967295 | 32 | 4 | | float | -3.438 | 3.438 | 32 | 4 | | double | -1.7308 | 1.7308 | 64 | 8 | A palavra "signed" em parêntesis é considerada opcional, pois por omissão um qualquer tipo de dados numérico é considerado "signed" (bipolar). Ns microcontroladores AVR //int// = //short// \\ No PC //int// = //long// \\ A linguagem C não tem um tipo de dados que represente uma string (conjunto de carateres). Em vez disso são utilizados vetores de carateres (assunto que será abordado adiante), e são utilizados carateres ASCII onde a cada caracter alfabético é representado um valor numérico. ==== Variáveis ==== Um programa pode utilizar um tipo de espações de memória pré-definidos, a isto chamamos variáveis. Os nomes das variáveis podem incluir qualquer caratere do alfabeto latino, números ou //underscores//, desde que o primeiro caractere não seja um caractere numérico. Quando se declara uma variável num programa, é necessário preceder o nome da variável com o tipo de dados desejado. Por forma a atribuir-se um valor a uma variável é utilizado o sinal de igualdade (=). A seguir apresenta-se um exemplo que ilustra a utilização de variáveis: // char type variable c declaration char c; // Value is given to variable c. c = 65; c = 'A'; // A has in ASCII character map also value 65 // int type variable i20 declaration and initialization int i20 = 55; // Declaration of several unsigned short type variables unsigned short x, y, test_variable; ==== Constantes ==== As constantes são declaradas da mesma maneira que as variáveis, apenas precedendo a palavra //const// com o tipo de dados respetivo. Uma constante nunca altera o seu valor durante a execução de um programa. Um exemplo de utilização de constantes: // int type constant declaration const int x_factor = 100; ==== Estruturas ==== Os tipos básicos de dados podem ser re-agrupados em estruturas por forma a criarem-se tipos de dados mais complexos, recorrendo à palavra //struct//. Uma estrutura representa um tipo de dados combinado, este tipo é declarado com a palavra //typedef//. Um exemplo sobre estruturas, sua criação e utilização de tipos de dados complexos: // Declaration of a new data type "point" typedef struct { // x and y coordinates and color code int x, y; char color; } point; // declaration of a variable as data type of point point p; // Assigning values for point variable p.x = 3; p.y = 14; ==== Vetores ==== Os tipos básicos de dados podem ser organizados em vetores. Os vetores podem ter várias dimensões (tabelas, cubos, etc.). Seguem-se exemplos da utilização de vetores de uma e duas dimensões respetivamente: // Declaration of one- and two-dimensional arrays char text[3]; int table[10][10]; // Creating a string from char array text[0] = 'H'; // Char text[1] = 'i'; // Char text[2] = 0; // Text terminator (0 B) // Assigning new value for one element. table[4][3] = 1; ===== Operadores ===== As variáveis, constantes e valores retornados de funções podem ser utilizados na composição de operações. O resultado de uma operação pode ser atribuído a uma variável, pode ser utilizado como parâmetro para outras funções ou como valor em diversas estruturas de controlo. ==== Operadores aritméticos ==== A linguagem C suporta a generalidade dos operadores aritméticos, como a soma (+), subtração (-), multiplicação (*), divisão (/) e o módulo (%). Seguem-se alguns exemplos ilustrativos da utilização destes operadores: int x, y; // Modulo, multiplication and assigning value // x gets value of 9 x = (13 % 5) * 3; // Adding-assigning operator // x gets value of 14 x += 5; // Quick style method for subtracting 1 // x gets value of 13 x--; ==== Operadores lógicos ==== Os operadores lógicos na linguagem C são compostos pela negação NOT (!), multiplicação lógica AND (&&) e a adição lógica (||). Seguem-se exemplos da utilização destes operadores: bool a, b, c; // Initialization a = true; b = false; // Negation // c will get a value of false because a is true c = !a; // Logic multiplication // c will get a value of false because one of the operators is false c = a && b; // Logic addition // c will get a value of true because one of the operators is true c = a || b; **NOTA!** O tipo de dados //bool// na linguagem C, na realidade não existe, pelo que em alternativa geralmente são utilizados valores inteiros para a representação destes valores, em que o valor 0 representa //Falso//, e qualquer outro valor diferente de 0 representa //Verdadeiro//. Por exemplo, na biblioteca do HomeLab, o tipo de dados //bool// é representado pelo tipo de dados //unsigned char//. A constante //Verdadeiro// é então representada pelo valor 1 e //Falso// representado pelo valor 0. ==== Operadores relacionais e de igualdade ==== Os valores lógicos são geralmente resultado de uma comparação entre variáveis. Os operadores de igualdade são: (==) //igual a//, (!=) //diferente//, (>) //maior que//, (>=) //maior ou igual que//, (<) //menor que//, (<=) //menor ou igual que//. Segue-se um exemplo de utilização destes operadores: int x = 10, y = 1; // greater than operation which is true // brackets around the operation are only for clarity bool b = (5 > 4); // Not equal to operation // The result is false b = (4 != 4); // Arithmetic, equality and logic operations altogether // b is false because the first operator of logic multiplication is false b = (x + 4 > 15) && (y < 4); ==== Operações de bit ==== As operações de //bit// são utilizadas para manipulação de dados em formato binário. Estas apenas podem ser aplicadas a tipos de dados inteiros. As operações de //bit// são bastante semelhantes às operações lógicas, com a única diferença que porque estas são aplicadas diretamente a cada um dos bits que compõem o valor, e não apenas ao conjunto que compõem o número. As operações de //bit// que existem na Linguagem C são a inversão (~), conjunção (&), disjunção (|), anti-valência (^), rotação à esquerda (<<) e a rotação à direita (>>). // Declaration of unsigned 8 bit char type variable // Variable value is 5 in decimal system, 101 in binary system unsigned char c = 5; // Disjunction of c with a digit 2 (010 in binary) // c value will become 7 (111 in binary) c = c | 2; // Bit left shift by 2 // c value will become 28 (11100 in binary) c = c << 2; As operações de //bit// são essenciais na manipulação de registos de um microcontrolador. Estes registos serão descritos adiante no capítulo de registos do AVR. ===== Funções ===== As funções definem partes de um programa que pode ser denominadas e invocadas pelo nome. As funções podem incluir parâmetros de entrada e permitem retornar um valor de saída. Se a função não retorna nenhum valor, esta função é definida com o tipo //void//. Se a função não possui parâmetros de entrada, em versões mais antigas da Linguagem C, o tipo //void// também deve ser incluído dentro dos parêntesis da sua declaração. Segue-se um exemplo de uma função que adiciona dois números inteiros e outro de uma função que não retorna nenhum valor. // Declaration of 2 int type parameter function // The function returns int type value int sum(int a, int b) { // Addition of 2 variables and returning of their sum return a + b; } // Function without parameters and no return output void power_off(void) { } Para utilizar-se uma função, esta deve ser invocada. Para isso, é necessário que a função seja declarada antes de ser invocada. Um exemplo com a invocação de uma função: int x; int y = 3; // Calling an addition function // Parameetriteks on muutuja ja konstandi väärtus // The parameters are variable and constant x = sum(y, 5); // The call of a power off function // No parameters power_off(); A execução de um programa em Linguagem C é sempre iniciada na função //main//. ===== Declarações ===== ==== Declarações If/Else ==== As declarações condicionais, permitem a execução condicional do código de um programa com base em operações lógicas e/ou relacionais. Uma declaração condicional utiliza a palavra //if//. Exemplo: // Statement is true and operation x = 5 will be executed // because 2 + 1 is higher than 2 if ((2 + 1) > 2) x = 5; // If x equals 5 and y equals 3 then the following code will be executed if ((x == 5) && (y == 3)) { // Random action y = 4; my_function(); } Um //if// permite também adicionar uma cláusula //else// que só é executada em caso do valor Falso. Exemplo: // Is x equal with 5 ? if (x == 5) { // Random action z = 3; } // If this is false then x might be equal with 6 else if (x == 6) { // Random action q = 3; } // If x was not 5 nor 6 ... else { // Random action y = 0; } ==== Declaração Switch ==== Quando é necessário comparar operações e variáveis com várias combinações de diferentes valores, é geralmente recomendável que se use em alternativa uma comparação com base na declaração //switch//. Exemplo da sua utilização: int y; // Switch statement for comparing y switch (y) { // is y equal to 1 ? case 1: // Random action function1(); break; // is y equal to 2 ? case 2: // Random action function2(); break; // All other cases default: // Random action functionX(); // break operation not needed, // because the comparison ends anyway } ===== Loops ===== Os //loops// permitem-nos executar código várias vezes. ==== while loop ==== O código encapsulado por um //while// é executado até que a condição entre parêntesis obtenha o valor Falso. Exemplo: int x = 0; // Loop will execute until x is smaller than 5 while (x < 5) { // x incrementation x++; } ==== for loop ==== O loop //for// assemelha-se ao loop //while//, excepto que as operações que este engloba são executadas antes da condição de e a verificação da condição é sempre efetuada no fim de cada ciclo. Exemplo: int i, x = 0; // i is equal to 1 at the beginning of the loop. // Loop will be executed until i is smaller than 5. // i will be incremented in the end of every loop cycle. for (i = 0; i < 5; i++) { // x addition by 2 x += 2; } // here x value is 10 ==== Saída de loops ==== A iteração de ciclos //while// ou //for// pode ser terminada com a instrução //break//. Para retomar a próxima iteração de um ciclo evitanto a execução do código que se segue pode ser feita com um //continue//. Por exemplo: int x = 0, y = 0; // Infinite loop because 1 is logic true while (1) { // Exit the the loop cycle if x becomes 100 if (x >= 100) break; // x incrementation to end loop at some time x++; // If x is 10 or less then the next cycle is started if (x <= 10) continue; // y incrementation y++; } // Here y value is 90 ==== Operações de texto ==== As operações de texto são geralmente utilizadas em microcontroladores para mostrar caracteres e texto num ecrã LCD, por exemplo. ==== sprintf ==== A função //sprintf// é bastante simular à função //printf// mais comumente utilizada na Linguagem C. A diferença entre estas é que o resultado desta função é carregado numa variável em vez do //standard output//. return = sprintf(variable, parameter_text, parameters); Exemplo: int r = sprintf(buffer, "%d pluss %d on %d", a, b, a+b); Esta função carrega a variável passada como primeiro argumento com texto formatado, texto este que é passado como segundo argumento da função, ao qual podem ser atribuídos valores com os seus restantes argumentos. O uso da função //sprintf// permitirá compôr texto mais complexo de maneira mais simples. Como retorno, esta função devolve o tamanho do texto que foi carregado na variável e no caso de erro, um valor negativo é retornado. Exemplo: sprintf(x, "%d. is first", 1); // the same result can be achieved also: x = "1. is first"; sprintf(x, "%s is %d years old", "Juku", 10); // the same result can be achieved also: x = "Juku is 10 years old"; %s e %d neste exemplosão parâmetros que irão ser substituídos pelos valores dos dois últimos parâmetros da função, respetivamente. O número de parâmetros deve igualar ao número de variáveis utilizadas na expressão. No primeiro exemplo, o parâmetro %d toma o valor 1. No segundo exemplo, os parâmetros %s e %d são substituídos pelos valores das variáveis, "Juku" e 10 respetivamente. Esta ordem de substituição dos parâmetros é respetiva à ordem em que se apresentam os valores. Existem vários descrições para os diferentes tipos de dados: ^ Parameter ^ Description ^ Example ^ | %c | Char | a | | %i or %d | Integer| 123 | | %f | Real number | 3,14 | | %s | Text | example| | %X | Hexadecimal number| 3F | #include int main () { char buffer [50]; int n, a=5, b=3; n=sprintf (buffer, "%d plus %d is %d", a, b, a+b); printf ("\"%s\" is %d digits long\n",buffer,n); return 0; } ==== Funções genéricas ==== A biblioteca standard da Linguagem C (stdlib.h) inclui funções que permitem a simplificação de várias operações e conversões mais comuns ==== Função aleatória ==== Não é fácil gerar um número aleatório num microcontrolador. Primeiro, é necessário dar como parâmetro de entrada um //gerador// que servirá como base para a geração do conjunto de números aleatórios. Este conjunto, se for sempre baseado no mesmo número //gerador//, será sempre igual. Por forma a tornar o resultado desta função mais aleatório, geralmente utiliza-se como valor //gerador//, um dos valores recolhidos de um dos pinos do ADC do microcontrolador. Exemplo: srand(100); rand(); Exemplo de geração de um número aleatório na gama de 1-16: #include int x; x=rand() % 16; Para uma descrição mais detalhada de todas as funções incluídas na Linguagem C: [[http://www.cplusplus.com/reference/clibrary/|http://www.cplusplus.com/reference/clibrary/]]