simple examples of how to

Sunday, December 13, 2009

MySQL in java

http://www.roseindia.net/jdbc/jdbc-mysql/mapping-mysql-data-types-in-java.shtml

mysql example site

http://www.mysqltutorial.org/

mysql c api example

MySQL C API proramming tutorial
About this tutorial

This is a C programming tutorial for the MySQL database. It covers the basics of MySQL programming with the C API.
About MySQL database

MySQL logo MySQL is a leading open source database management system. It is a multi user, multithreaded database management system. MySQL is especially popular on the web. It is a one of the parts of the very popular LAMP platform. Linux, Apache, MySQL, PHP. MySQL is owned by a swedish company called MySQL AB. This company and Trolltech are prominent open source companies. MySQL database is available on most important OS platforms. It runs under BSD Unix, Linux, Windows or Mac. Wikipedia and YouTube use MySQL. These sites manage millions of queries each day. MySQL comes in two versions. MySQL server system and MySQL embedded system.
First example

Our first example will test one MySQL function call.

#include my_global.h
#include mysql.h

int main(int argc, char **argv)
{
printf("MySQL client version: %s\n", mysql_get_client_info());
}

The mysql_get_client_info() shows the MySQL client version.

gcc version.c -o version `mysql_config --cflags --libs`

Here is how we compile the code example.

$ ./version
MySQL client version: 5.0.38

#include
#include

We include necessary header files. mysql.h is the most important header file for MySQL function calls. my_global.h includes some global declarations a functions. Among other thing, it includes the standard input/output header file.

printf("MySQL client version: %s\n", mysql_get_client_info());

This code line outputs the version of the MySQL client. For this, we use the mysql_get_client_info() function call.
Creating a database

The next code example will create a database.

#include
#include

int main(int argc, char **argv)
{

MYSQL *conn;

conn = mysql_init(NULL);

if (conn == NULL) {
printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn));
exit(1);
}

if (mysql_real_connect(conn, "localhost", "zetcode", "passwd", NULL, 0, NULL, 0) == NULL) {
printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn));
exit(1);
}

if (mysql_query(conn, "create database testdb")) {
printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn));
exit(1);
}


mysql_close(conn);

}

The code example connects to the MySQL database system and creates a new database called testdb.

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| testdb |
+--------------------+
3 rows in set (0.00 sec)

This is the proof, that the database was created.

We include error checking in this example. It is important to check for possible errors. Database programming is a field, where many things might go wrong. For clarity reasons, later examples will be without error checking. I suppose that it is clear for everyone, that it is every programmers responsibility to do error checking.

The code example can be divided into these parts.

* Initiation of a connection handle structure
* Creation of a connection
* Execution of a query
* Closing of the connection

MYSQL *conn;

We declare a pointer to a MYSQL structure. This structure will serve as a connection handler.

conn = mysql_init(NULL);

The mysql_init() function obtains a connection handler.

if (conn == NULL) {
printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn));
exit(1);
}

We check the return value. If the mysql_init() function fails, we print the error message and terminate the application.

if (mysql_real_connect(conn, "localhost", "zetcode", "passwd", NULL, 0, NULL, 0) == NULL) {
printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn));
exit(1);
}

The mysql_real_connect() function establishes a connection to the database. We provide connection handler, host name, user name and passwor parameters to the function. The other four parameters are the database name, port number, unix socket and finally the client flag.

if (mysql_query(conn, "create database testdb")) {
printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn));
exit(1);
}

The mysql_query() executes the SQL statement. In our case, the statement creates a new database.

mysql_close(conn);

Finally, we close the database connection.
Creating and populating a table

The next code example will create a table and insert some data into it.

#include
#include

int main(int argc, char **argv)
{

MYSQL *conn;

conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "zetcode", "passwd", "testdb", 0, NULL, 0);

mysql_query(conn, "CREATE TABLE writers(name VARCHAR(25))");

mysql_query(conn, "INSERT INTO writers VALUES('Leo Tolstoy')");
mysql_query(conn, "INSERT INTO writers VALUES('Jack London')");
mysql_query(conn, "INSERT INTO writers VALUES('Honore de Balzac')");
mysql_query(conn, "INSERT INTO writers VALUES('Lion Feuchtwanger')");
mysql_query(conn, "INSERT INTO writers VALUES('Emile Zola')");

mysql_close(conn);

}

We don't use any new MySQL function call here. We use mysql_query() function call to both create a table and insert data into it.

mysql_real_connect(conn, "localhost", "zetcode", "passwd", "testdb", 0, NULL, 0);

We connect to testdb database. The user name is zetcode and password is passwd.

mysql_query(conn, "CREATE TABLE writers(name VARCHAR(25))");

Here we create a table named writers. It has one varchar column.

mysql_query(conn, "INSERT INTO writers VALUES('Leo Tolstoy')");

We insert one writer name into the writers table.

mysql> show tables;
+------------------+
| Tables_in_testdb |
+------------------+
| writers |
+------------------+
1 row in set (0.00 sec)


We show tables in the database.

mysql> select * from writers;
+-------------------+
| name |
+-------------------+
| Leo Tolstoy |
| Jack London |
| Honore de Balzac |
| Lion Feuchtwanger |
| Emile Zola |
+-------------------+
5 rows in set (0.00 sec)

We select all data from the table.
Retrieving data from the database

In the next example, we will retrieva data from a table.

Steps:

* Create a connection
* Execute query
* Get the result set
* Fetch all available rows
* Free the result set

#include
#include

int main(int argc, char **argv)
{

MYSQL *conn;
MYSQL_RES *result;
MYSQL_ROW row;
int num_fields;
int i;

conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "zetcode", "passwd", "testdb", 0, NULL, 0);

mysql_query(conn, "SELECT * FROM writers");
result = mysql_store_result(conn);

num_fields = mysql_num_fields(result);

while ((row = mysql_fetch_row(result)))
{
for(i = 0; i < num_fields; i++)
{
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}

mysql_free_result(result);
mysql_close(conn);

}

The example prints all names from the writers table.

$ ./select
Leo Tolstoy
Jack London
Honore de Balzac
Lion Feuchtwanger
Emile Zola

mysql_query(conn, "SELECT * FROM writers");

We execute the query, that will retrieve all names from the writers database.

result = mysql_store_result(conn);

We get the result set.

num_fields = mysql_num_fields(result);

We get the number of fields in the table.

while ((row = mysql_fetch_row(result)))
{
for(i = 0; i < num_fields; i++)
{
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}

We fetch the rows and print them to the screen.

mysql_free_result(result);

We free the resources.
Column headers

In the next example, we will retrieve data and show the their column names from the table.

For this, we will create a new table friends.

mysql> create table friends (id int not null primary key auto_increment,
name varchar(20), age int);

mysql> insert into friends(name, age) values('Tom', 25);
mysql> insert into friends(name, age) values('Elisabeth', 32);
mysql> insert into friends(name, age) values('Jane', 22);
mysql> insert into friends(name, age) values('Luke', 28);

We insert some data into the table.

#include
#include

int main(int argc, char **argv)
{

MYSQL *conn;
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL_FIELD *field;

int num_fields;
int i;

conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "zetcode", "passwd", "testdb", 0, NULL, 0);

mysql_query(conn, "SELECT * FROM friends");
result = mysql_store_result(conn);

num_fields = mysql_num_fields(result);

while ((row = mysql_fetch_row(result)))
{
for(i = 0; i < num_fields; i++)
{
if (i == 0) {
while(field = mysql_fetch_field(result)) {
printf("%s ", field->name);
}
printf("\n");
}
printf("%s ", row[i] ? row[i] : "NULL");
}
}
printf("\n");

mysql_free_result(result);
mysql_close(conn);
}

The example is similar to the previous one. It just adds column header names to it.

while(field = mysql_fetch_field(result)) {
printf("%s ", field->name);
}

The mysql_fetch_field() call returns a MYSQL_FIELD structure. We get the column header names from this structure.

$ ./headers
id name age
1 Tom 25
2 Elisabeth 32
3 Jane 22
4 Luke 28

And this is the output of our program.
Inserting images into MySQL database

Some people prefer to put their images into the database, some prefer to keep them on the file system for their applications. Technical difficulties arise when we work with millions of images. Images are binary data. MySQL database has a special data type to store binary data called BLOB (Binary Large Object).

mysql> describe images;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | | |
| data | mediumblob | YES | | NULL | |
+-------+------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

This is the table, that we will use in our example. It can be created by the following SQL statement.

create table images(id int not null primary key, data mediumblob);

#include
#include

int main(int argc, char **argv)
{
MYSQL *conn;

int len, size;
char data[1000*1024];
char chunk[2*1000*1024+1];
char query[1024*5000];

FILE *fp;

conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "zetcode", "passwd", "testdb", 0, NULL, 0);

fp = fopen("image.png", "rb");
size = fread(data, 1, 1024*1000, fp);

mysql_real_escape_string(conn, chunk, data, size);

char *stat = "INSERT INTO images(id, data) VALUES('1', '%s')";
len = snprintf(query, sizeof(stat)+sizeof(chunk) , stat, chunk);

mysql_real_query(conn, query, len);

fclose(fp);
mysql_close(conn);
}

In this example, we will insert one image into the images table. The image can be max 1 MB.

fp = fopen("image.png", "rb");
size = fread(data, 1, 1024*1000, fp);

Here we open the image and read it into the data array.

mysql_real_escape_string(conn, chunk, data, size);

Binary data can obtain special characters, that might cause troubles in the statements. We must escape them. The mysql_real_escape_string() puts the encoded data into the chunk array. In theory, every character might be a special character. That's why the chunk array two times as big as the data array. The function also adds a terminating null character.

char *stat = "INSERT INTO images(id, data) VALUES('1', '%s')";
len = snprintf(query, sizeof(stat)+sizeof(chunk) , stat, chunk);

These two code lines prepare the MySQL query.

mysql_real_query(conn, query, len);

Finally, we execute the query.
Selecting images from MySQL database

In the previous example, we have inserted an image into the database. In the following example, we will select the inserted image back from the database.

#include
#include

int main(int argc, char **argv)
{
MYSQL *conn;
MYSQL_RES *result;
MYSQL_ROW row;

unsigned long *lengths;
FILE *fp;

conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "zetcode", "passwd", "testdb", 0, NULL, 0);

fp = fopen("image.png", "wb");

mysql_query(conn, "SELECT data FROM images WHERE id=1");
result = mysql_store_result(conn);

row = mysql_fetch_row(result);
lengths = mysql_fetch_lengths(result);

fwrite(row[0], lengths[0], 1, fp);
mysql_free_result(result);

fclose(fp);
mysql_close(conn);
}

In this example, we will create an image file from the database.

fp = fopen("image.png", "wb");

We open a file for writing.

mysql_query(conn, "SELECT data FROM images WHERE id=1");

We select an image with id 1.

row = mysql_fetch_row(result);

The row contains raw data.

lengths = mysql_fetch_lengths(result);

We get the length of the image.

fwrite(row[0], lengths[0], 1, fp);

We create the image file using the fwrite() standard function call.

SQL: enable remote access

By default, MySQL database server remote access disabled for security reasons. However, some time you need to provide the remote access to database server from home or from web server.

Solution1

Step # 1: Login over ssh

First, login over ssh to remote MySQL database server

Step # 2: Enable networking

Once connected you need edit the mysql configuration file
my.cfg using text editor such as vi.

In Debian Linux file is located at /etc/mysql/my.cnf

# vi /etc/my.cnf

Step # 3: Once file open, locate line that read as [mysqld]

Make sure line skip-networking is commented (or remove line) and add following line

bind-address=YOUR-SERVER-IP

For example, if your MySQL server IP is 172.20.5.2 then entire block should be look like as follows:

[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
language = /usr/share/mysql/English
bind-address = 172.20.5.2

# skip-networking
....
..
....

Where,

bind-address : IP address to bind to.
skip-networking : Don’t listen for TCP/IP connections at all. All interaction with mysqld must be made via Unix sockets. This option is highly recommended for systems where only local requests are allowed. Since you need to allow remote connection this line should removed from file or put it in comment state.

Step# 4 Save and Close the file.

Restart your mysql service to take change in effect

# /etc/init.d/mysql restart

Step # 5 Grant access to remote IP address

# mysql -u root –p mysql

Grant access to new database

If you want to add new database called foo for user bar and remote IP 162.54.10.20 then you need to type following commands at mysql> prompt:

mysql> CREATE DATABASE foo;

mysql> GRANT ALL ON foo.* TO bar@'162.54.10.20' IDENTIFIED BY 'PASSWORD';

Grant access to existing database

Let us assume that you are always making connection from remote IP called 162.54.10.20 for database called webdb for user webadmin then you need to grant access to this IP address. At mysql> prompt type following command for existing database:

mysql> update db set Host='162.54.10.20' where Db='webdb';

mysql> update user set Host='162.54.10.20' where user='webadmin';

Step # 5: Logout of MySQL

Type exit command to logout mysql

mysql> exit

Step # 6: Test it

From remote system type command

$ mysql -u webadmin –h 172.20.5.2 –p

You can also use telnet to connect to port 3306 for testing purpose

$ telnet 172.20.5.2 3306

Solution 2

All you need to do is specify remote mysql host with –h option. For example to connect remote mysql server called server.test.com you need to type command as follows

$ mysql –u ruchi –h server.test.com -p

OR if you with to use MySQL server ip address (172.20.1.101)

Friday, December 4, 2009

what is volatile in c?

From somewhere in the internet...

8.4. Const and volatile

These are new in Standard C, although the idea of const has been borrowed from C++. Let us get one thing straight: the concepts of const and volatile are completely independent. A common misconception is to imagine that somehow const is the opposite of volatile and vice versa. They are unrelated and you should remember the fact.
Since const declarations are the simpler, we'll look at them first, but only after we have seen where both of these type qualifiers may be used. The complete list of relevant keywords is
char long float volatile
short signed double void
int unsigned const
In that list, const and volatile are type qualifiers, the rest are type specifiers. Various combinations of type specifiers are permitted:
char, signed char, unsigned char
int, signed int, unsigned int
short int, signed short int, unsigned short int
long int, signed long int, unsigned long int
float
double
long double
A few points should be noted. All declarations to do with an int will be signed anyway, so signed is redundant in that context. If any other type specifier or qualifier is present, then the int part may be dropped, as that is the default.
The keywords const and volatile can be applied to any declaration, including those of structures, unions, enumerated types or typedef names. Applying them to a declaration is called qualifying the declaration—that's why const and volatile are called type qualifiers, rather than type specifiers. Here are a few representative examples:
volatile i;
volatile int j;
const long q;
const volatile unsigned long int rt_clk;
struct{
const long int li;
signed char sc;
}volatile vs;
Don't be put off; some of them are deliberately complicated: what they mean will be explained later. Remember that they could also be further complicated by introducing storage class specifications as well! In fact, the truly spectacular
extern const volatile unsigned long int rt_clk;
is a strong possibility in some real-time operating system kernels.
8.4.1. Const

Let's look at what is meant when const is used. It's really quite simple: const means that something is not modifiable, so a data object that is declared with const as a part of its type specification must not be assigned to in any way during the run of a program. It is very likely that the definition of the object will contain an initializer (otherwise, since you can't assign to it, how would it ever get a value?), but this is not always the case. For example, if you were accessing a hardware port at a fixed memory address and promised only to read from it, then it would be declared to be const but not initialized.
Taking the address of a data object of a type which isn't const and putting it into a pointer to the const-qualified version of the same type is both safe and explicitly permitted; you will be able to use the pointer to inspect the object, but not modify it. Putting the address of a const type into a pointer to the unqualified type is much more dangerous and consequently prohibited (although you can get around this by using a cast). Here is an example:
#include
#include

main(){
int i;
const int ci = 123;

/* declare a pointer to a const.. */
const int *cpi;

/* ordinary pointer to a non-const */
int *ncpi;

cpi = &ci;
ncpi = &i;

/*
* this is allowed
*/
cpi = ncpi;

/*
* this needs a cast
* because it is usually a big mistake,
* see what it permits below.
*/
ncpi = (int *)cpi;

/*
* now to get undefined behaviour...
* modify a const through a pointer
*/
*ncpi = 0;

exit(EXIT_SUCCESS);
}
Example 8.3
As the example shows, it is possible to take the address of a constant object, generate a pointer to a non-constant, then use the new pointer. This is an error in your program and results in undefined behaviour.
The main intention of introducing const objects was to allow them to be put into read-only store, and to permit compilers to do extra consistency checking in a program. Unless you defeat the intent by doing naughty things with pointers, a compiler is able to check that const objects are not modified explicitly by the user.
An interesting extra feature pops up now. What does this mean?
char c;
char *const cp = &c;
It's simple really; cp is a pointer to a char, which is exactly what it would be if the const weren't there. The const means that cp is not to be modified, although whatever it points to can be—the pointer is constant, not the thing that it points to. The other way round is
const char *cp;
which means that now cp is an ordinary, modifiable pointer, but the thing that it points to must not be modified. So, depending on what you choose to do, both the pointer and the thing it points to may be modifiable or not; just choose the appropriate declaration.
8.4.2. Volatile

After const, we treat volatile. The reason for having this type qualifier is mainly to do with the problems that are encountered in real-time or embedded systems programming using C. Imagine that you are writing code that controls a hardware device by placing appropriate values in hardware registers at known absolute addresses.
Let's imagine that the device has two registers, each 16 bits long, at ascending memory addresses; the first one is the control and status register (csr) and the second is a data port. The traditional way of accessing such a device is like this:
/* Standard C example but without const or volatile */
/*
* Declare the device registers
* Whether to use int or short
* is implementation dependent
*/

struct devregs{
unsigned short csr; /* control & status */
unsigned short data; /* data port */
};

/* bit patterns in the csr */
#define ERROR 0x1
#define READY 0x2
#define RESET 0x4

/* absolute address of the device */
#define DEVADDR ((struct devregs *)0xffff0004)

/* number of such devices in system */
#define NDEVS 4

/*
* Busy-wait function to read a byte from device n.
* check range of device number.
* Wait until READY or ERROR
* if no error, read byte, return it
* otherwise reset error, return 0xffff
*/
unsigned int read_dev(unsigned devno){

struct devregs *dvp = DEVADDR + devno;

if(devno >= NDEVS)
return(0xffff);

while((dvp->csr & (READY | ERROR)) == 0)
; /* NULL - wait till done */

if(dvp->csr & ERROR){
dvp->csr = RESET;
return(0xffff);
}

return((dvp->data) & 0xff);
}
Example 8.4
The technique of using a structure declaration to describe the device register layout and names is very common practice. Notice that there aren't actually any objects of that type defined, so the declaration simply indicates the structure without using up any store.
To access the device registers, an appropriately cast constant is used as if it were pointing to such a structure, but of course it points to memory addresses instead.
However, a major problem with previous C compilers would be in the while loop which tests the status register and waits for the ERROR or READY bit to come on. Any self-respecting optimizing compiler would notice that the loop tests the same memory address over and over again. It would almost certainly arrange to reference memory once only, and copy the value into a hardware register, thus speeding up the loop. This is, of course, exactly what we don't want; this is one of the few places where we must look at the place where the pointer points, every time around the loop.
Because of this problem, most C compilers have been unable to make that sort of optimization in the past. To remove the problem (and other similar ones to do with when to write to where a pointer points), the keyword volatile was introduced. It tells the compiler that the object is subject to sudden change for reasons which cannot be predicted from a study of the program itself, and forces every reference to such an object to be a genuine reference.
Here is how you would rewrite the example, making use of const and volatile to get what you want.
/*
* Declare the device registers
* Whether to use int or short
* is implementation dependent
*/

struct devregs{
unsigned short volatile csr;
unsigned short const volatile data;
};

/* bit patterns in the csr */
#define ERROR 0x1
#define READY 0x2
#define RESET 0x4

/* absolute address of the device */
#define DEVADDR ((struct devregs *)0xffff0004)

/* number of such devices in system */
#define NDEVS 4

/*
* Busy-wait function to read a byte from device n.
* check range of device number.
* Wait until READY or ERROR
* if no error, read byte, return it
* otherwise reset error, return 0xffff
*/
unsigned int read_dev(unsigned devno){

struct devregs * const dvp = DEVADDR + devno;

if(devno >= NDEVS)
return(0xffff);

while((dvp->csr & (READY | ERROR)) == 0)
; /* NULL - wait till done */

if(dvp->csr & ERROR){
dvp->csr = RESET;
return(0xffff);
}

return((dvp->data) & 0xff);
}
Example 8.5
The rules about mixing volatile and regular types resemble those for const. A pointer to a volatile object can be assigned the address of a regular object with safety, but it is dangerous (and needs a cast) to take the address of a volatile object and put it into a pointer to a regular object. Using such a derived pointer results in undefined behaviour.
If an array, union or structure is declared with const or volatile attributes, then all of the members take on that attribute too. This makes sense when you think about it—how could a member of a const structure be modifiable?
That means that an alternative rewrite of the last example would be possible. Instead of declaring the device registers to be volatile in the structure, the pointer could have been declared to point to a volatile structure instead, like this:
struct devregs{
unsigned short csr; /* control & status */
unsigned short data; /* data port */
};
volatile struct devregs *const dvp=DEVADDR+devno;
Since dvp points to a volatile object, it not permitted to optimize references through the pointer. Our feeling is that, although this would work, it is bad style. The volatile declaration belongs in the structure: it is the device registers which are volatile and that is where the information should be kept; it reinforces the fact for a human reader.
So, for any object likely to be subject to modification either by hardware or asynchronous interrupt service routines, the volatile type qualifier is important.
Now, just when you thought that you understood all that, here comes the final twist. A declaration like this:
volatile struct devregs{
/* stuff */
}v_decl;
declares the type struct devregs and also a volatile-qualified object of that type, called v_decl. A later declaration like this
struct devregs nv_decl;
declares nv_decl which is not qualified with volatile! The qualification is not part of the type of struct devregs but applies only to the declaration of v_decl. Look at it this way round, which perhaps makes the situation more clear (the two declarations are the same in their effect):
struct devregs{
/* stuff */
}volatile v_decl;
If you do want to get a shorthand way of attaching a qualifier to another type, you can use typedef to do it:
struct x{
int a;
};
typedef const struct x csx;

csx const_sx;
struct x non_const_sx = {1};

const_sx = non_const_sx; /* error - attempt to modify a const */
8.4.2.1. Indivisible Operations

Those of you who are familiar with techniques that involve hardware interrupts and other ‘real time’ aspects of programming will recognise the need for volatile types. Related to this area is the need to ensure that accesses to data objects are ‘atomic’, or uninterruptable. To discuss this is any depth would take us beyond the scope of this book, but we can at least outline some of the issues.
Be careful not to assume that any operations written in C are uninterruptable. For example,
extern const volatile unsigned long realtimeclock;
could be a counter which is updated by a clock interrupt routine. It is essential to make it volatile because of the asynchronous updates to it, and it is marked const because it should not be changed by anything other than the interrupt routine. If the program accesses it like this:
unsigned long int time_of_day;

time_of_day = real_time_clock;
there may be a problem. What if, to copy one long into another, it takes several machine instructions to copy the two words making up real_time_clock and time_of_day? It is possible that an interrupt will occur in the middle of the assignment and that in the worst case, when the low-order word of real_time_clock is 0xffff and the high-order word is 0x0000, then the low-order word of time_of_day will receive 0xffff. The interrupt arrives and increments the low-order word of real_time_clock to 0x0 and then the high-order word to 0x1, then returns. The rest of the assignment then completes, with time_of_day ending up containing 0x0001ffff and real_time_clock containing the correct value, 0x00010000.
This whole class of problem is what is known as a critical region, and is well understood by those who regularly work in asynchronous environments. It should be understood that Standard C takes no special precautions to avoid these problems, and that the usual techniques should be employed.
The header ‘signal.h’ declares a type called sig_atomic_t which is guaranteed to be modifiable safely in the presence of asynchronous events. This means only that it can be modified by assigning a value to it; incrementing or decrementing it, or anything else which produces a new value depending on its previous value, is not safe.