标签归档:cpp

RSS feed of cpp

最后更新于 .

今天发文比较多,哈,实在是觉得知识就该及时沉淀下来,时间长了难免记忆会模糊。 OK,直接切入正题,之前http://t.vimer.cn上提过正在开发的fuload压力测试框架,由于是想拿python做胶水语言,所以不可避免的涉及到了进程间通信的问题。 简单来说就是,一个python写的主进程与多个c写的处理进程通信的问题。主进程启动之后,会启动多个c的处理进程,主进程会对处理进程发送数据,并控制处理进程。 这种情况在server的编写中比较常见,为了解耦一般会将接受数据的进程与处理进程分开,在c中的实现一般是主进程先fork出子进程,然后在子进程中调用exec将自身替换为处理进程,进程id不变。这样主进程即可拿到所有的子进程id进行统一管理。 python当然也可以通过这种方式来实现,fork+execv即可完美重现,但是这可是无所不能的python呀,是否有更好的方式呢? 有的!python2.4之后引入了subprocess模块,通过它,我们将不再需要繁琐的调用fork,execv等,其主要函数如下:

class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn ...

最后更新于 .

今天在开例会的时候,提到其他小组要做一个通用任务系统,会涉及到C++调用其他语言脚本开发的逻辑。之前倒是听互娱那边的同事说过,他们都是嵌入lua来进行脚本编程,但自己从来没试过。
而作为一个严重中毒的vim+python爱好者,其实我每天都在用vim直接执行python命令(如出名的pyflakes插件),想知道vim是怎么实现的,所以就自己试了一下。
由于家里没有linux开发环境,所以就在windows下用 Mingw + makefile的方式开发了。
先写一个简单的py程序:helloworld.py

def hello():
       print"hello,world!"

然后来写我们的c++代码:

py.cpp

#include<Python.h>//前面所做的一切配置都是为了调用这个头文件和相关库
int main()
{
    Py_Initialize();//使用python之前,要调用Py_Initialize();这个函数进行初始化
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");
    PyObject * pModule = NULL;//声明变量
    PyObject * pFunc = NULL;// 声明变量
    pModule =PyImport_ImportModule ...

最后更新于 .

在python,c#等语言中,string都是默认提供split这个函数的,C++里面却没有默认实现,但又经常会用到,所以就简单实现了一个:

int SplitString(const string &srcStr,const string &splitStr,vector<string> &destVec)
{
    if(srcStr.size()==0)
    {   
        return 0;
    }   
    size_t oldPos,newPos;
    oldPos=0;
    newPos=0;
    string tempData;
    while(1)
    {   
        newPos=srcStr.find(splitStr,oldPos);
        if(newPos!=string::npos)
        {   
            tempData = srcStr.substr(oldPos,newPos-oldPos);
            destVec.push_back(tempData);
            oldPos=newPos+splitStr ...

最后更新于 .

今天在测试的时候发现一个很诡异的问题,语言描述不清楚,直接看代码吧。为了测试各种可能性,我写了两种类继承的代码如下:

#!/usr/bin/python
#-*- coding: UTF-8 -*-

import re
import sys
import os
import json
import simplejson

class Foo(object):
    _data = 1

    def __init__(self,data):
        self._data = data
    def ShowFoo(self):
        print 'Foo',self._data

class Bar(Foo):
    def __init__(self,data):
        super(Bar,self).__init__(data)
    def ShowBar(self):
        #会报错 ...

最后更新于 .

今天在翻unix网络编程的时候,无意中看到了使用匿名定义结构体/类定义数组的一段代码。

于是写了测试代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;

struct st
{
    int a;
    int b;
    char *p;
    int c;
}sts[]={
    {1,1,"hh",1},
    {2,2,"ff",2}
};

class CObj
{
    public:
        int a;
        string s;
        int b;

}objs[]={
    {1,"x",11},
    {2,"y",22}
};

int main(int argc, const ...

最后更新于 .

注:本文是公司同事的一个分享,由于很有代表性,特分享在此,希望对大家有用。 上次welkin在处理一个豆瓣的cgi时遇到1个奇怪的问题,就是对一个string对象的修改引起了另一个string对象的同步修改。后来定位到原有,是因为有函数对string对象的buf内容直接进行了操作,破坏了“写时拷贝”的规则。下面这个例子说明了问题是如何产生的,已经如何避免:

int main()   
{   
    string str1 = "abcd";   
    string str2 = str1;   
    char *p1 = const_cast<char*>(str1.c_str());   
    p1[0] = 'o';   
    //这里str1和str2同时被修改了   
    printf("%s %s\n", str1.c_str(), str2.c_str());   
    string str3 = "abcd";   
    string str4 = str3;   
    char *p2 = &(str3[0]);   
    p2[0] = 'o';   
    //这里只有str3被修改,str4不变   
    printf ...

最后更新于 .

首先庆祝一下QQ餐厅正式不删档公测,本以为终于可以不用那么晚发版本了,结果昨晚入口CGI出现问题,折腾到凌成4点多,杯具……

先截个餐厅的图给大家看一下:

canting

先来介绍下背景,公司是使用自己写的webserver,然后用fastcgi的方式运行CGI,结果前端返回502错误。和运维的同学确认后,了解到当CGI在执行完却没有返回给webserver任何数据,就会报502错误。
检查了一下代码,任何出错都会有错误返回。
于是strace了一下进程,发现在出现一次如下的错误之后,以后的请求就全部都会出错。

修改

其实这个CGI和平常的CGI没有什么区别,只是由于用到了模板类,所以使用cout来进行输出而不是printf,结果问题就出在了cout上。

与printf不同,cout在出错之后,会保存出错的状态,而由于fastcgi是一直在内存里的,所以在cout第一次出错之后,后面的就全部都会出错。
解决的方法是:
在每次开始cout数据之前,调用一下cout.clear()

之后,问题得到解决,在出现上图中的错误之后,以后的数据也一样可以正常输出。

但是这样毕竟不是办法,因为当访问量非常高的时候,用户遇到错误的概率也是非常高的。

以为是cout的数据不全,于是尝试在CGI输出的最后,我加了一行:cout<<flush;,结果发现出错的概率反而变高了许多,于是就去掉了。

目前猜测的问题还是底层库可能有头文件和.a不一致的问题,之前碰到一个应为这个问题写越界的,还有一个也是这个原因结果编译成可执行时,cout会core,看来底层库的统一也是件大事啊

参考文章:
endl cout 缓冲区执行时立即刷新

最后更新于 .

最近在做项目的时候,遇到一个问题,即结构体内的字段可能会在未来的时间内不停的增加(不会减少或者删除),所以在打包解包的时候就会涉及到版本兼容的问题,并且是向前和向后同时兼容。

我们先来看一下,如果结构体的内容永远不变,那么我们用结构体自解析的方法:


typedef struct _farmbase_land1
{/*{{{*/
unsigned char ID;
unsigned char bitmap;
_farmbase_land1()
{
ID = 0;
bitmap = 0;
}
int Output(unsigned int /*ver*/,char*& buff,int& iLen,int iMaxLen)
{/*{{{*/
int needLen = sizeof(unsigned char)*2;
if(needLen>iMaxLen)
{
return FBErrSystemNoMem;
}
char *t_Buff = buff;
*(unsigned char*)t_Buff = ID;
t_Buff+=sizeof(unsigned char);
*(unsigned char*)t_Buff = bitmap;
t_Buff+=sizeof(unsigned char);
iLen ...

最后更新于 .

编写代码的过程中,经常会输出一些调试信息到屏幕上,一般会调用printf这类的函数。
但是当调试解决之后,我们需要手工将这些地方删除或者注释掉。
再这次的项目中就用到类似问题,为了调试程序,再一些地方输出了很多的信息,随着项目的调试,输出的信息越来越多。于是就面临着,如何处理这些输出信息的语句。
简单删掉,不仅有一定的工作量,而且也不能保证之后就不出现问题,出现问题后这些信息还是有用的。
不去掉,带着调试信息就上线,这是明显不允许的。
于是就想到了一个可行的办法。如下:

void myprintf(char* fmt, ...)
{
}
#ifdef DEBUG
#define printf(fmt, args...) myprintf(fmt, ##args)
#endif


调试阶段带着DEBUG调试,正式上线就可以把printf变成一个空函数了。
这样做的一个潜在风险是可能会导致默写glib函数需要调用printf输出错误log也给取消掉了。
令人欣慰的是,大部分glib调用的应该是fprintf。
虽然问题解决了,但是我对args...以及##args还是不太了解。上网找了些gcc手册的资料如下:
带有可变参数的宏(Macros with a Variable Number of Arguments)
在1999年版本的ISO C ...

最后更新于 .

本篇主要是一些使用示例,由于部分代码是来源网上,原作者已经无法考证,所以如有原作者看到,可以告诉我,我给注明~

上一篇链接--libcurl的使用总结(一)

另:文末附有所有代码的打包下载,均在suse 10下编译运行通过

1.下载文件到本地

/*==============================================
#  Author:          DanteZhu - https://www.vimer.cn
#  Email:           dantezhu@vip.qq.com
#  FileName:        test_download.cpp
#  Version:         1.0
#  LastChange:      2010-03-09 14:20:44
#  Description:     
#  History:         
============================================*/
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include "curl/curl.h"
using namespace std;
static char ...