Showing posts with label example. Show all posts
Showing posts with label example. Show all posts

Monday, August 06, 2007

"else" or not after if ?

到底 if 之後要不要接 else 呢?

問題總是沒有永遠對的答案
if statement 後面可以沒有 else statement
但有 else statement 總是不會出錯

有多少的bugs, 是掛在這種邏輯問題上面

大部分的人會先注意如何 function work
等到 function work 之後, 也接近準備 release 階段
很容易沒有考慮到 exception 的發生

這對應到 code 的本身
也就是
只注意到 if 成立之後, 而忽略 if 失敗的另一面

為了避免遇到這樣的問題
最好是根據code的大小來安排code配置
比如先寫比較短的程式碼 再寫比較長的程式碼

if (1) {
/* short successful statement */
} else {
/*
...
long failure statement
...
*/
}

or on the contrary,

if (!0) {
/* short failure statement */
} else {
/*
...
long successful statement
...
*/
}

Tuesday, June 05, 2007

Message Queue example

The time to use Message Queue I know is internal logging, and that's the way it used.

msgq_rcv <- MSG Queue <- msgq_snd

sample code below,
msgq.h

#ifndef _MSGQ_H_
#define _MSGQ_H_

#define MSGQ_PATH "/tmp"
#define MSGQ_ID 111
#define MSG_LEN 128

typedef struct {
long mtype; // MUST
time_t time;
char msg[MSG_LEN+1];
} msgq_t ;

#endif /* _MSGQ_H_ */

msgq_rcv.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <time.h>
#include "msgq.h"

int main(int argc, char *argv[])
{
key_t key;
int msgqid;
msgq_t msg;

if ( (key=ftok(MSGQ_PATH, MSGQ_ID)) == -1) {
perror("ftok");
return -1;
}

if ( (msgqid = msgget(key, 0666|IPC_CREAT)) == -1) {
perror("msgget");
return -1;
}

while (1) {
if (-1==msgrcv(msgqid, &msg, sizeof(msg), 0, 0)) {
perror("msgrcv");
return -1;
}
printf("%s->%s\n", ctime(&msg.time), msg.msg);
}

return 0;
}

msgq_snd.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <time.h>
#include <string.h>
#include "msgq.h"

int main(int argc, char *argv[])
{
key_t key;
int msgqid;
msgq_t msg;

if ( (key=ftok(MSGQ_PATH, MSGQ_ID)) == -1) {
perror("ftok");
return -1;
}

if ( (msgqid = msgget(key, 0666|IPC_CREAT)) == -1) {
perror("msgget");
return -1;
}

while (1) {
memset(&msg, 0x00, sizeof(msg));
msg.mtype = 1; // MUST
fgets(msg.msg, sizeof(msg.msg)-1, stdin);
time(&(msg.time));
if (-1==msgsnd(msgqid, (msgq_t*)&msg, sizeof(msg), 0)) {
perror("msgsnd");
return -1;
}
}
}

read/write the binary content to file

An example shown here to present
1) how to write the binary content to a file
2) and then read the content from it

Some steps
1) Prepare chunks of memory
Usually the content will be records of memory of any structure type, in case it can be restored back with the structure in step4.
2) Output to a file
Open a file first by open()/fopen(), and then write the records to the file by write()/fwrite(). Of course, all the content can be written once or one by one, it depends on your design decision. Remember to close the file at last.
3) Input the file
We want to read the binary content. First we should open the file and read the content by read()/fread(). How many size we need? Actually, we would not have no idea the real amount of record, but we know the basic element should be the original structure type. so we can use the structure as the element size and then get the chunks of the same size one by one. Finally and without any exception, when we can get nothing, we have gotten all the records without any damage.
4) Recognize the content
The way to recognize the binary content is usually to cast the binary record to be of the original structure type.

Pitfall here,
Usually, we can get the exact all the records without any damage. But exceptions always happen around, so we should have some preventions in hand. The common exception here is the damaged data, so how to make sure the data integrity is the major task. A way to keep data integrity is append the checksum to the real data. so before storing the data, we calculating the checksum and append the result to the data, and after we read the content, we calculate the checksum and compare with the old one. If they match, the data isn't damaged. If not, trouble happened.

Another issue concerned here is the structure layout. Usually, the structure size will always be the multiples of 4, which is defined by the WORD size of the processor. If the actual size is not the multiples of 4, the compiler will expand it to be the multiples by stuffing the hole up. So make sure the structure as compact as possible.

Issue of binary data exchange between different byte order systems is also the problem. It should be the responsibility of the application of upper layer to make sure the portability.

#include <stdio.h>
#include <time.h>
#include <string.h>

#define USER_LEN 10
#define PASS_LEN 10
#define TOTAL_ACCOUNTS 10

typedef struct {
time_t create_time;
char user[USER_LEN+1];
char pass[PASS_LEN+1];
char reserved[2];
} account_t ;

int main(int argc, char *argv[])
{
int i=0;
FILE *fd;
account_t acc[TOTAL_ACCOUNTS];

// writer
memset(acc, 0x00, sizeof(acc[0])*TOTAL_ACCOUNTS);
for (i=0; i< TOTAL_ACCOUNTS; ++i) {
snprintf(acc[i].user, sizeof(acc[0].user)-1, "user%d", i);
snprintf(acc[i].pass, sizeof(acc[0].pass)-1, "pass%d", i);
time(&acc[i].create_time);
}
fd = fopen("accounts.bin", "wb");
fwrite(acc, sizeof(acc[0]), TOTAL_ACCOUNTS, fd);
fclose(fd);

// reader
memset(acc, 0x00, sizeof(acc[0])*TOTAL_ACCOUNTS);
fd = fopen("accounts.bin", "rb");
for (i=0; !feof(fd) ; ++i) {
fread(&acc[i], sizeof(acc[0]), 1, fd);
if ( feof(fd) ) // A pitfall here
break;

printf("%d,%s/%s/%s\n", i, acc[i].user, acc[i].pass
, ctime(&acc[i].create_time) );
}
fclose(fd);
return 0;
}


Usually, hexdump is alwasy useful to dump the binary content out.