La Vita è Bella
Friday, July 11, 2008
Don't try to fool compilers
There's a macro in ACE to eliminate a compiler warning:
379 // Some compilers complain about "statement with no effect" with (a).
380 // This eliminates the warnings, and no code is generated for the null
381 // conditional statement. @note that may only be true if -O is enabled,
382 // such as with GreenHills (ghs) 1.8.8.
383 # define ACE_UNUSED_ARG(a) do {/* null */} while (&a == 0)
But when I use this macro, gcc 4.3 will complain:
warning: the address of ‘a’ will never be NULL
tags: dev, compiler, gcc, warning, ace
12:25:52 by fishy - dev - Permanent Link
Monday, July 09, 2007
Deal with 2 versions of iconv.h
There're 2 versions of iconv.h in which the iconv() have different prototypes.
In Debian, it's:
43 extern size_t iconv (iconv_t __cd, char **__restrict __inbuf,
44 size_t *__restrict __inbytesleft,
45 char **__restrict __outbuf,
46 size_t *__restrict __outbytesleft);
And in other systems, such as Mac OS X, it's:
83 extern size_t iconv (iconv_t cd, const char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);
So you can see that the second parameter, "inbuf", can be "const char **" or "char **"
It will make a big problem while writing code for both systems. One resolution is to use condition compile ("#ifdef" blah blah...), but RoachCock@newsmth give me another (and much better) resolution: use operator overload (so it's C++ only):
133 struct iconv_param_adapter {
134 iconv_param_adapter(const char**p) : p(p) {}
135 iconv_param_adapter(char**p) : p((const char**)p) {}
136 operator char**() const
137 {
138 return (char**)p;
139 }
140 operator const char**() const
141 {
142 return (const char**)p;
143 }
144 const char** p;
145 };
When you calling "iconv()", call it like this:
111 size_t res = iconv(data, iconv_param_adapter(&s), &inbytesleft, &outnew, &outbytesleft);
Thank you RoachCock!
tags: iconv, debian, c, cxx, cpp
15:58:25 by fishy - dev - Permanent Link
2 comments - no trackbacks yet - karma: -5 [+/-]
Monday, June 18, 2007
Add GBK encoding support to expat
expat is a good XML parser, light and quick. But it only support latin1, UTF-8 and UTF-16 naturally, if you want to use it to deal with other encoding XML's, you need to set a unknown encoding handler.
I use libiconv to convert the GBK string to Unicode for expat.
First, implement a function to pass to XML_SetUnknownEncodingHandler:
int
XML_Stream_Parser::xml_unknown_encoding(void* data, const char* name, XML_Encoding* info) {
iconv_t cd;
if(strncasecmp(name, "GB", 2) != 0 || (cd = iconv_open("UCS-2BE", name)) == (iconv_t)-1) { // not GB, unsupported
fprintf(stderr, "can't convert %s\n", name);
return 0;
}
for(size_t i=0; i<128; i++) info->map[i] = i;
for(size_t i=128; i<256; i++) info->map[i] = -2;
info->convert = XML_Stream_Parser::xml_convert_gb;
info->release = XML_Stream_Parser::xml_convert_release;
info->data = cd;
return 1;
}
In this function, I tell expat that for GBK encoding, ASCII 0~127 is left as is, and ASCII 128~255 will need to be dealt together with the next byte.
Then implement the "convert" and "release" functions:
int
XML_Stream_Parser::xml_convert_gb(void* data, const char* s) {
const size_t out_initial = 4;
size_t inbytesleft = 2, outbytesleft = out_initial;
char *out = new char[out_initial], *outnew = out;
size_t res = iconv(data, &s, &inbytesleft, &outnew, &outbytesleft);
int ret = 0;
if(res == (size_t)-1) {
fprintf(stderr, "error in conversion\n");
delete []out;
return '?';
}
for(size_t i = 0; i < out_initial - outbytesleft; i++)
ret = (ret<<8) + (unsigned char)out[i];
delete []out;
return ret;
}
void
XML_Stream_Parser::xml_convert_release(void* data) {
iconv_close(data);
}
In "convert", I use iconv to convert the string to unicode, and return the unicode to expat.
The limitation in this interface is that it can't deal with 4-byte GB18030 codes, as I can't judge whether it's a 4-byte code just by the first code.
Anyway, I suggest that all XML should be encoded to UTF-8, so that this is unneeded
tags: expat, encoding, iconv, libiconv, gbk
18:46:30 by fishy - dev - Permanent Link
Tuesday, May 22, 2007
Simple SQLite test C program, without callbacks
I need some efficient way for Miao for word database, and I guess SQLite is the solution. So I wrote this simple test program to get familiar with SQLite API. (read more for the program)
And there's something should be kept in mind: don't use "`"s.
As I used to use MySQL before, I always put "`" in SQL statements, for example:
create table `foo` (`bar` int)
It's OK in SQLite command line program, but not in the C library.
When I execute a SQL query with "`", I'll get this error message:
sql error #1: unrecognized token: "`"
So I deleted "`"s in the SQL statement, but still get this error message:
sql error #4: malformed database schema - unrecognized token: "`"
This really drive me crazy, as I don't know what's wrong. But finally I've got the reason: that's because there's "`" in the "create table" statement. So I recreated the table and rerun the program, it's finally OK now.
00:38:33 by fishy - dev - Permanent Link
Wednesday, April 25, 2007
Vim Tip: vim and ctags
If you use vim for programming, then you can't live without ctags (can you?). ctags generate the "tags" file, vim and its plugins use this file to help your programming more efficiently.
By default, vim will only use the "tags" file under your current working directory. You can use this command to see it:
:set tags?
Generally, your "tags" file under you current working directory won't contain informations about system libraries (glibc, stl, etc.). If you miss them, you can generate tags file for your system libraries, and ask your vim to load them:
set tags+=/usr/local/include/tags
set tags+=/usr/include/tags
If you are working on a big project, which have many subdirectories, the "tags" file under each working directory may be not enough, as you also need some information about the functions under other subdirectories. So you can generate a "tags" file under your project root, and ask vim to load it when editing a file within your project:
autocmd BufEnter ~/work/myproj/* :setlocal tags+=~/work/myproj/tags
Thanks for Ryan Phillips, you can also add "tags;" (notice the semicolon) to your tags so that vim will automatically look up "tags" file in the file tree (":help file-searching" for document):
set tags+=tags;
To make it easier to use, I've also made a script named "projtags.vim" so that you need only set your project directories in your vimrc:
let g:ProjTags = ["~/work/proj1"]
let g:ProjTags+= [["~/work/proj2", "~/work/proj2.tags"]]
Happy vimming
tags: vim, ctags, tags, project
02:37:29 by fishy - dev - Permanent Link
2 comments - no trackbacks yet - karma: 0 [+/-]
Wednesday, September 13, 2006
virtual class in c++
Here's a example to make a virtual class in c++, similar to "interface" in Pascal and Java:
1 #include <stdio.h>
2 #include <string>
3 #include <vector>
4
5 class base_foo {
6 public:
7 virtual std::string name() { return "base_foo"; }
8 };
9
10 class foo: public base_foo {
11 public:
12 std::string name() { return "foo"; }
13 };
14
15 class bar: public base_foo {
16 public:
17 std::string name() { return "bar"; }
18 };
19
20 int main() {
21 std::vector<base_foo*> foo_list;
22 foo f;
23 bar b;
24 foo_list.push_back(&f);
25 foo_list.push_back(&b);
26 printf("%s\n%s\n",
27 foo_list[0]->name().c_str(),
28 foo_list[1]->name().c_str());
29 return 0;
30 }
The result of this program is:
foo
bar
tags: cpp, c, virtual, interface
22:51:34 by fishy - dev - Permanent Link
3 comments - no trackbacks yet - karma: 1 [+/-]
Wednesday, July 12, 2006
libmysqlclient didn't report error while insert duplicate data in primary keys.
22:34:33 by fishy - dev - Permanent Link




