Index
- Operators in C and C++
- Member access through pointer (->)
- Structure
- typedef
- Callback
- Clearing Bits & Setting Bits (&= and |=)
- Bit Fields
- const
- static
- Preprocessing or Preprocessor directives
- Including files
- Conditional compilation
- Macro definition and expansion
- Special macros and directives
Operators in C and C++
- Operators in C and C++, see WikipediA here.
Member access through pointer (->)
The member access expression has the form
expression -> member-name
where:
expression – an expression of type pointer to struct or union
member-name – an identifier that names a member of the struct or union pointed by expression
The member access through pointer expression designates the named member of the struct or union type pointed to by its left operand. Its value category is always lvalue
If the type pointed to by the left operand is const or volatile qualified, the result is also qualified. If the type pointed to by the left operand is atomic, the behavior is undefined.
#include <stdio.h> struct s {int x;}; int main(void) { struct s s={1}, *p = &s; p->x = 7; // changes the value of s.x through the pointer printf("%d\n", p->x); // prints 7 }
(From: cppreference)
Structure
A struct in the C programming language (and many derivatives) is a complex data type declaration that defines a physically grouped list of variables to be placed under one name in a block of memory, allowing the different variables to be accessed via a single pointer, or the struct declared name which returns the same address. The struct can contain many other complex and simple data types in an association, so is a natural organizing type for records like the mixed data types in lists of directory entries reading a hard drive (file length, name, extension, physical (cylinder, disk, head indexes) address, etc.), or other mixed record type (patient names, address, telephone… insurance codes, balance, etc.). (From: WikipediA)
In Italian language
Le strutture del C sostanzialmente permettono l’aggregazione di più variabili, in modo simile a quella degli array, ma a differenza di questi non ordinata e non omogenea (una struttura può contenere variabili di tipo diverso). Per denotare una struttura si usa la parola chiave struct seguita dal nome identificativo della struttura, che è opzionale.
(Da: html.it)
struct book { char titolo[100]; char autore[50]; int anno_pubblicazione; float prezzo; } biblio; (Da: html.it)
Per accedere alle variabili interne della struttura si usa l’operatore punto ‘.‘
Una variabile interna può essere poi manipolata come qualsiasi altra variabile.
(Da: html.it)
// Assign a value to the book price biblio.prezzo = 67.32; // Assign a variable int the year publication of the book int year = biblio.anno_pubblicazione; // Print the title of the book printf ("% s n", biblio.titolo); (Da: html.it)
typedef
typedef – creates an alias that can be used anywhere in place of a (possibly complex) type name. (From: cppreference)
// simple typedef typedef unsigned long ulong; // the following two objects have the same type unsigned long l1; ulong l2; // more complicated typedef typedef int int_t, *intp_t, (&fp)(int, ulong), arr_t[10]; // the following two objects have the same type int a1[10]; arr_t a2; // common C idiom to avoid having to write "struct S" typedef struct {int a; int b;} S, *pS; // the following two objects have the same type pS ps1; S* ps2; // error: storage-class-specifier cannot appear in a typedef declaration // typedef static unsigned int uint; // typedef can be used anywhere in the decl-specifier-seq long unsigned typedef int long ullong; // std::add_const, like many other metafunctions, use member typedefs template< class T> struct add_const { typedef const T type; }; typedef struct Node { struct listNode* next; // declares a new (incomplete) struct type named listNode } listNode; // error: conflicts with the previously declared struct name (From: cppreference)
In Italian language
Per definire nuovi tipi di dato viene utilizzata la funzione typedef.
L’uso di typedef, combinato con struct ci permette di creare tipi di dato molto complessi, come mostrato nell’esempio seguente:
typedef struct libro { char titolo[100]; char autore[50]; int anno_pubblicazione; float prezzo; } t_libro; t_libro guida = {"Guida al C", "Fabrizio Ciacchi", 2003, 45.2};
In questo modo abbiamo definito un nuovo tipo di nome t_libro, che non è altro che una struttura.
guida è la variabile creata di tipo t_libro.
Ora possiamo utilizzare il nuovo tipo come ogni altro, ad esempio possiamo creare un array di elementi di tipo t_libro.
t_libro raccolta[5000];
Per accedere agli elementi dell’array, o per inizializzare i valori, è sufficiente utilizzare l’indice per identificare l’elemento dell’array ed il punto (.) per accedere alle variabili interne del tipo t_libro.
// assegna un valore al prezzo del 341mo libro raccolta[340].prezzo = 67.32; // assegna ad una variabile int l'anno di pubblicazione del 659mo libro int anno = raccolta[658].anno_pubblicazione; // stampa il titolo del 23mo libro printf ("%s n", raccolta[22].titolo);
(Da: html.it)
Callback
(From: WikipediA)
A callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time.
This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback.
In all cases, the intention is to specify a function or subroutine as an entity[clarification needed] that is, depending on the language, more or less similar to a variable.
Programming languages support callbacks in different ways, often implementing them with subroutines, lambda expressions, blocks, or function pointers. (From: WikipediA)
In Italian language
Un callback (o, in italiano, richiamo) è, una funzione, o un “blocco di codice” che viene passata come parametro ad un’altra funzione.
In particolare, quando ci si riferisce alla callback richiamata da una funzione, la callback viene passata come parametro alla funzione chiamante.
In questo modo la chiamante può realizzare un compito specifico (quello svolto dalla callback).
Se invece ci si riferisce alla callback come funzione richiamata dal sistema operativo, di norma ciò si utilizza allo scopo di gestire particolari eventi: dal premere un bottone con il mouse, allo scrivere caratteri in un campo di testo.
Ciò consente, quindi, a un programma di livello più basso, di richiamare una funzione (o servizio) definita a un livello più alto. (From: WikipediA)
Clearing Bits & Setting Bits
Clearing Bits
PORTH &= 0xF5; // Changes bits 1 and 3 to zeros using C bit7 6 5 4 3 2 1 0 0xAF == 1 0 1 0 1 1 1 1 (PORTH value) 0xF5 == 1 1 1 1 0 1 0 1 0xA5 == 1 0 1 0 0 1 0 1 (result) PORTH &= ~0x0A; // Same as above but using inverting the bit mask // easier to see which bits are cleared
Setting Bits
PORTH |= 0x0A; // Set bits 1 and 3 to one using the OR bit7 6 5 4 3 2 1 0 0xA1 == 1 0 1 0 0 0 0 1 (PORTH value) 0x0A == 0 0 0 0 1 0 1 0 0xAB == 1 0 1 0 1 0 1 1 (result)
(From: Embedded Systems/C Programming)
Bit Fields
Bit fields are a topic that few C programmers have any experience with, although it has been a standardized part of the language for some time now.
Bit fields allow the programmer to access memory in unaligned sections, or even in sections smaller than a byte.
Let us create an example:
struct _bitfield { flagA : 1; flagB : 1; nybbA : 4; byteA : 8; }
The colon separates the name of the field from its size in bits, not bytes.
Suddenly it becomes very important to know what numbers can fit inside fields of what length.
For instance, the flagA and flagB fields are both 1 bit, so they can only hold boolean values (1 or 0) the nybbA field can hold 4 bits, for a maximum value of 15 (one hexadecimal digit).
Fields in a bitfield can be addressed exactly like regular structures.
For instance, the following statements are all valid:
struct _bitfield field; field.flagA = 1; field.flagB = 0; field.nybbA = 0x0A; field.byteA = 255;
(From: Embedded Systems/C Programming)
const
const is used to store a value in ROM or FLASH.
This declaration put the months in RAM.
char * months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", };
This declaration put the months in ROM or FLASH.
char const * months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", };
We inform the compiler that we promise to never modify months.
(From: Embedded Systems/C Programming)
static
The static keyword can accompany the declaration of one or more variables and / or functions, and takes on different meanings depending on the context in which it is used:
as part of a global or namespace
in the context of a function
as part of a class or struct
If it is used within a function, as in
int funz( ) { static int ciccio; }
It means that the integer variable ciccio SAVES its value between executions of func and any subsequent re-execution.
In Italian language
La parola static può accompagnare la dichiarazione di una o più variabili e/o funzioni, e assume diversi significati secondo il contesto in cui è utilizzata:
- nell’ambito globale o di un namespace
- nell’ambito di una funzione
- nell’ambito di una class o una struct
Se viene usata nell’ambito di una funzione, come in
int funz( ) { static int ciccio; }
significa che la variabile intera ciccio CONSERVA il proprio valore tra un’esecuzione di funz e un’eventuale esecuzione successiva.
Per le spiegazioni complete vedere UNIBO lab info
Preprocessing or Preprocessor directives
The C preprocessor or cpp is the macro preprocessor for the C and C++ computer programming languages.
The preprocessor provides the ability for the inclusion of header files, macro expansions, conditional compilation, and line control. (From: WikipediA)
Including files
One of the most common uses of the preprocessor is to include another file: #include
#include <file>
Putting the name of the include file Among the less than symbol (<) and That of greater than (>); in this form, the compiler’s going to look for the files present in the selected directory to include; and generally this default directory, and That Which Contains the libraries and files standards, coming for example stdio.h, stdlib.h, math.h, string.h, time.h and so on.
But if you want to include a file that is in the same folder of our program, we should use an alternative form, as follows:
#include "file"
Conditional compilation
The if-else directives #if, #ifdef, #ifndef, #else, #elif and #endif can be used for conditional compilation.
#if VERBOSE >= 2 print("trace message"); #endif
Translation can also be caused to fail by using the #error directive see the examples below.
#if RUBY_VERSION == 190 #error 1.9.0 not supported #endif #if defined USING_SQLITE && defined USING_MYSQL #error You cannot use both sqlite and mysql at the same time #endif #if !(defined USING_SQLITE && defined USING_MYSQL) #error You must use either sqlite or mysql #endif
Macro definition and expansion
There are two types of macros, object-like and function-like. Object-like macros do not take parameters; function-like macros do (although the list of parameters may be empty). The generic syntax for declaring an identifier as a macro of each type is, respectively:
// object-like macro #define <identifier> <replacement token list> // function-like macro, note parameters #define <identifier>(<parameter list>) <replacement token list> (From: WikipediA)
Examples:
#define NUMERO 5 #define QUADRATO(a) (a)*(a)
#include <stdio.h> #define NUMERO 5 #define QUADRATO(a) (a)*(a) int main() { int x; printf(“Numero : %d n”, NUMERO); x = QUADRATO(NUMERO); printf(“Quadrato: %d n”, x); #undef NUMERO #define NUMERO 7 printf(“Numero : %d n”, NUMERO); x = QUADRATO(NUMERO); printf(“Quadrato: %d n”, x); return 0; } (From: html)
Special macros and directives
Certain symbols are required to be defined by an implementation during preprocessing. These include __FILE__ and __LINE__, predefined by the preprocessor itself, which expand into the current file and line number. For instance the following:
// debugging macros so we can pin down message origin at a glance #define WHERESTR "[file %s, line %d]: " #define WHEREARG __FILE__, __LINE__ #define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__) #define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__) //... DEBUGPRINT("hey, x=%d\n", x);
prints the value of x, preceded by the file and line number to the error stream, allowing quick access to which line the message was produced on. Note that the WHERESTR argument is concatenated with the string following it.
The values of __FILE__ and __LINE__ can be manipulated with the #line directive.
The #line directive determines the line number and the file name of the line below. E.g.:
#line 314 "pi.c" printf("line=%d file=%s\n", __LINE__, __FILE__);
generates the printf function:
printf("line=%d file=%s\n", 314, "pi.c");
Source code debuggers refer also to the source position defined with __FILE__ and __LINE__.
This allows source code debugging, when C is used as target language of a compiler, for a totally different language.
The first C Standard specified that the macro __STDC__ be defined to 1 if the implementation conforms to the ISO Standard and 0 otherwise, and the macro __STDC_VERSION__ defined as a numeric literal specifying the version of the Standard supported by the implementation. (From: WikipediA)