Mar 22
就是前面那个 c/c++版 logger.h 到php的移植。使用基本一致。

代码详见: http://code.google.com/p/woj-land/source/browse/trunk/code/web/lib/logger.lib.php

另附针对此日志格式的php写的查看工具:
http://code.google.com/p/woj-land/source/browse/trunk/tools/logviewer/
Mar 10
LOGGER v0.0.3
A simple logger for c/c++ under linux, multiprocess-safe

---- CopyLeft by Felix021 @ http://www.felix021.com ----

一个最简单的使用这个日志系统的程序:
#include "logger.h"

int main()
{
    log_open("log.txt");
    log_add_info("id:1001");
    FM_LOG_DEBUG("test %d", 123);
    return 0;
}
记录日志内容为:
引用
--NOTICE-- [2010-03-10 18:10:18] [logger.h:91] log_open
--DEBUG-- [2010-03-10 18:10:18] [main.c:7] [id:1001] test 123
--NOTICE-- [2010-03-10 18:10:18] [logger.h:99] [id:1001] log_close
下载文件 (已下载 1053 次)

@ 2010-03-22 p.s. 增加了php移植版
Mar 4

花钱如流水v0.0.1 不指定

felix021 @ 2010-3-4 11:32 [IT » 程序设计] 评论(1) , 引用(0) , 阅读(4139) | Via 本站原创
花钱如流水 v0.0.1

By Felix021 @ 2010-03-04
http://www.felix021.com

一个PHP+MySQL的简易支出记录系统,提供一些最基本功能,界面简单,方便手机使用。

安装:随便找一个数据库,导入tbl.sql,然后修改config.php里的相关参数即可使用。

(界面很难看,代码很难看,原则:够用就好。)
下载文件 (已下载 552 次)
Jan 24
参考这里的教程写的: http://www.developer.com/article.php/3417381

同时也终于知道了stmt原来是Statement的简写,惭愧。。。
import java.sql.*;

public class Jdbc11 {
    public static void main (String args[]) {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Statement stmt = null;
            String url     = "jdbc:mysql://localhost:3306/test";
            String dbuser  = "root";
            String dbpass  = "123456";
            String dbname  = "felix021";
            String tblname = "users";

            Connection con = DriverManager.getConnection(url, dbuser, dbpass);
            stmt = con.createStatement();
            System.out.println("URL: " + url);
            System.out.println("Connection: " + con);

            //建库
            stmt.executeUpdate("CREATE DATABASE IF NOT EXISTS " + dbname);
            stmt.executeUpdate("USE " + dbname);

            //建表
            stmt.executeUpdate("DROP TABLE IF EXISTS " + tblname);
            stmt.executeUpdate(
                    "CREATE TABLE " + tblname + "(\n" +
                    "  `id` INT PRIMARY KEY AUTO_INCREMENT, \n" +
                    "  `name` CHAR(20) NOT NULL, \n" +
                    "  `description` varchar(255) DEFAULT NULL\n" +
                    ")"
                    );

            //插入
            int count = stmt.executeUpdate(
                    "INSERT INTO " + tblname + "\n" +
                    "(`id`, `name`, `description`) VALUES \n" +
                    "(NULL, 'a', 'ooxx'), \n" +
                    "(NULL, 'b', NULL), \n" +
                    "(NULL, 'c', 'haha'), \n" +
                    "(NULL, 'd', 'hoho')"
                    );
            System.out.println("Inserted " + count + " rows");

            //statement for resultset
            stmt = con.createStatement(
                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);

            //查询
            ResultSet rs = stmt.executeQuery("SELECT * FROM " + tblname);
            System.out.println("All results are listed below:");
            while (rs.next()) {
                int    id           = rs.getInt("id");
                String name         = rs.getString("name");
                String description  = rs.getString("description");
                System.out.println(
                        "id=" + id + ", " +
                        "the name is " + name + ", " +
                        description
                        );
            }

            //删表
            stmt.executeUpdate("DROP TABLE " + tblname);

            //删库
            stmt.executeUpdate("DROP DATABASE " + dbname);
        }
        catch (SQLException sqlE) {
            System.out.println("SQL Error: " + sqlE);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Jan 18
今天windy在群里提出一个问题: 为什么下面这段代码输出了why?
$arr = 'windy';
if (isset($arr['why'])) {
  echo 'why';
}

因为已经有结果了,反推过去,很容易就会想到,php把字符串当作数组来用了。再通过
echo $arr['why'];
验证一下,发现输出的是w, 也就是$arr{0}的值,可以大致得出一个结论:当把字符串当作数组使用的时候,会自动把索引转换成整形,然后再当作字符串的偏移量读取返回。

由于此结论仅为猜测,想进一步证实,但是对php代码不熟悉,翻了zend_hash.c等文件都没找到北,因此请教了雪候鸟大人,得知真正的处理代码位于
@ php-5.2.8/Zend/zend_execute.c +1026
static void zend_fetch_dimension_address(temp_variable *result, zval **container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC)
这个函数的作用是:将container_ptr所指向的container这个容器中,索引为dim的值取出放在result所指定的内存中去。

具体实现的代码是
1063     switch (Z_TYPE_P(container)) {
1064         zval **retval;
....
1099         case IS_STRING: { //如果这个容器是string
1100                 zval tmp;
1101
1102                 if (dim == NULL) {
1103                     zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
1104                 }
1105
1106                 if (Z_TYPE_P(dim) != IS_LONG) {  //如果偏移量的类型不是LONG
1107                     switch(Z_TYPE_P(dim)) {
1108                         /* case IS_LONG: */  
1109                         case IS_STRING:  
1110                         case IS_DOUBLE:
1111                         case IS_NULL:
1112                         case IS_BOOL:
1113                             /* do nothing */   //允许STRING, DOUBLE, NULL, BOOL四种类型
1114                             break;
1115                         default: //其他类型都报错
1116                             zend_error(E_WARNING, "Illegal offset type");
1117                             break;
1118                     }
1119
1120                     tmp = *dim;
1121                     zval_copy_ctor(&tmp);
1122                     convert_to_long(&tmp);
1123                     dim = &tmp;  //将原来的dim转换成LONG
1124                 }      
1125                 switch (type) {
1126                     case BP_VAR_R:
1127                     case BP_VAR_IS:
1128                     case BP_VAR_UNSET:
1129                         /* do nothing... */
1130                         break;
1131                     default:
1132                         SEPARATE_ZVAL_IF_NOT_REF(container_ptr);
1133                         break;
1134                 }
1135                 if (result) { //存放结果
1136                     container = *container_ptr;
1137                     result->str_offset.str = container;
1138                     PZVAL_LOCK(container);
1139                     result->str_offset.offset = Z_LVAL_P(dim);
1140                     result->var.ptr_ptr = NULL;
1141                     if (type == BP_VAR_R || type == BP_VAR_IS) {
1142                         AI_USE_PTR(result->var);
1143                     }
1144                 }
1145                 return;
1146             }
1147             break;

简单写了一点注释,只能大致看懂逻辑,其他边边角角的,暂时就没时间看了:'(
Jan 18

一段挺好玩的PHP源码 不指定

felix021 @ 2010-1-18 17:20 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(3244) | Via 本站原创
@ php-5.2.8/Zend/zend_builtin_functions.c
1120 #ifdef ZEND_TEST_EXCEPTIONS
1121 ZEND_FUNCTION(crash)
1122 {
1123     char *nowhere=NULL;
1124
1125     memcpy(nowhere, "something", sizeof("something"));
1126 }
1127 #endif
Jan 11

收藏: PHP的hash函数 不指定

felix021 @ 2010-1-11 17:31 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(3664) | Via 本站原创
更多内容,参见laruence大牛的这篇: http://www.laruence.com/2009/07/23/994.html

这么短一段代码,有这么多考究的地方,很值得学习:
1. 5381
2. hash << 5 + hash  --> hash * 33 (times 33算法)
3. -= 8
4. switch, break
...

static inline ulong zend_inline_hash_func(char *arKey, uint nKeyLength)
{
    register ulong hash = 5381;

    /* variant with the hash unrolled eight times */
    for (; nKeyLength >= 8; nKeyLength -= 8) {
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
    }
    switch (nKeyLength) {
        case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 1: hash = ((hash << 5) + hash) + *arKey++; break;
        case 0: break;
EMPTY_SWITCH_DEFAULT_CASE()
    }
    return hash;
}
Jan 4
在发现有atoi这个函数之后的一段时间里(converts a string to an integer, cppreference.com),每当我需要把integer转换成字符串的时候,我就会想当然地写上itoa,直到编译器告诉我,这个函数不存在。反复几次以后,我终于记住了没有itoa,记住了应该用sprintf(现在想想,是应该用snprintf才对)。直到今天我才意识到自己从来就没有仔细想过,为什么有atoi,却没有itoa。也许还是自己求知欲太低了。

原因其实很简单,简单地说,就是因为不好处理返回值。atoi, atof, atol等函数之所以可以在C标准库中存在,可以列出来的有两个必要条件:一,需求使然;二,返回值类型是基本类型,可以使用匿名变量传递。itoa之所以不在C标准库中,我觉得并不是没有需求,而是因为返回值是字符串,也就是char数组,处理起来比较纠结。

在C里面,字符串始终是个硬伤。如果非要设计这么一个函数,有三种可选的办法:

一,使用一个static的char数组(貌似printf就是这么做的吧)。这有2个问题,1是数组的长度是固定的(当然,简单处理的话可以认为int最多就那么几位,只要初始化某个足够的长度肯定就OK),2是每次调用会覆盖上次的结果,特别地,会导致非线程安全。

二,每次调用,在函数内部malloc一段空间,写入,返回该空间的首地址。存在问题是,分配的空间函数内无法自行释放,需要调用者安排一个free,而这个free是非常容易被忽略的,这就存在了潜在的内存泄漏风险。

三,要求传入一个分配好空间的指针,函数将转换结果写入。这样实际上就是sprintf的做法,重复造轮子。而且还要考虑内存越界访问的问题,再增加一个参数n,然后这就是snprintf做的事情....

综合起来的结果就是:太麻烦了,不实现。

最后,推荐云风的一篇文章,这里探讨了与以上内容比较相关的”一个 C 接口设计的问题“
http://blog.codingnow.com/2009/01/c_interface.html
分页: 7/21 第一页 上页 2 3 4 5 6 7 8 9 10 11 下页 最后页 [ 显示模式: 摘要 | 列表 ]