标签归档:c

RSS feed of c

最后更新于 .

查看错误代码errno是调试程序的一个重要方法。当linuc C api函数发生异常时,一般会将errno变量(需include errno.h)赋一个整数值, 不同的值表示不同的含义,可以通过查看该值推测出错的原因。在实际编程中用这一招解决了不少原本看来莫名其妙的问题。比较麻烦的是每次都要去linux源代码里面查找错误代码的含义,现在把它贴出来,以后需要查时就来这里看了。
以下来自linux 的内核代码中的/usr/include/asm/errno.h


#ifndef _I386_ERRNO_H
#define _I386_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 ...

最后更新于 .

1, c语言中,结构体struct中不能包括函数的,而在C++中struct中可以包括函数。
2,C++中结构体和类可以通用,区别主要表现在访问控制方面:struct中默认是public,而 class中默认的是private。
3,构造函数最重要的作用是创建对象的本身,C++中每个类可以拥有多个构造函数,但必须至少有一个构造函数,当一个类中没有显式提供任何构造函数,C++编辑器自动提供一个默认的不带参数的构造函数,这个默认的构造函数只负责构造对象,不做任何初始化工作。但在一个类中只要自己定义一个构造函数,不管带参不带参,编辑器不再提供默认的不带参的构造函数了。构造函数没有返回值。
4,析构函数当一个对象生命周期结束时候被调用来回收对象占用的内存空间。一个类只需有一个析构函数。析构函数没有返回值也不的带参数。
5,析构函数的作用与构造函数相反,对象超出起作用范围对应的内存空间被系统收回,或被程序用delete删除的时候,对象的析构函数被调用。
6,函数的重载条件:函数的参数类型、个数不同,才能构成函数的重载。重载是发生在同一个类中。
7,类是抽象的,不占用具体物理内存,只有对象是实例化的,是占用具体物理内存的。
8,this指针是隐含指针,指向对象本身(this指针不是指向类的),代表了对象的地址。所有的对象调用的成员函数都是同一代码段,但每个对象都有自己的数据成员。当对象通过调用它的成员函数来访问它的数据成员的时候,成员函数除了接收实参外 ...

最后更新于 .

所有线程都有一个线程号,也就是Thread ID。其类型为pthread_t。通过调用pthread_self()函数可以获得自身的线程号。
下面说一下如何创建一个线程。
通过创建线程,线程将会执行一个线程函数,该线程格式必须按照下面来声明:

void * Thread_Function(void *)

创建线程的函数如下:

int pthread_create(pthread_t *restrict thread,
      const pthread_attr_t *restrict attr,
      void *(*start_routine)(void*), void *restrict arg);

下面说明一下各个参数的含义:

thread:所创建的线程号。
attr:所创建的线程属性,这个将在后面详细说明。
start_routine:即将运行的线程函数。
art:传递给线程函数的参数。


下面是一个简单的创建线程例子:

#include <pthread.h>
#include <stdio.h>
/* Prints x’s to stderr. The parameter is unused ...

最后更新于 .

如何将一个字符串转换成大写或者小写?这是字符串匹配中经常需要做的事情,然而C++的Standard Library并没有提供将std::string转成大写和小写的功能,只有在提供将char转成大写(toupper)和小写(tolower)的功能而已。 但我们可以利用STL的transform配合toupper/tolower,完成std::string转换大(小)写的功能,也看到 模版编程 的威力了,一个transform函数,可以适用于任何类型,且只要自己提供 函数 ,就可完成任何Transform的动作。

C++

#include <iostream>
#include <string>
#include <cctype>
#include <algorithm>
using namespace std;
int main() {
    string s = "Clare";
    // toUpper
    transform(s.begin(), s.end(), s.begin(), ::toupper);
    // toLower
    //transform(s.begin ...

最后更新于 .

C++的string提供了replace方法来实现字符串的替换,但是对于将字符串中某个字符串全部替换这个功能,string并没有实现,我们今天来做的就是这件事。
首先明白一个概念,即string替换所有字符串,将”12212″这个字符串的所有”12″都替换成”21″,结果是什么?
可以是22211,也可以是21221,有时候应用的场景不同,就会希望得到不同的结果,所以这两种答案都做了实现,代码如下:

#include   <string>   
#include   <iostream>   
using   namespace   std;   
string&   replace_all(string&   str,const   string&   old_value,const   string&   new_value)   
{   
    while(true)   {   
        string::size_type   pos(0);   
        if(   (pos=str.find(old_value))!=string::npos   )   
            str.replace(pos,old_value.length(),new_value);   
        else   break;   
    }   
    return   str ...

最后更新于 .

想必大家在学C/C++编程的一开始就会学习如何在文件中循环获取没一行的数据,但是我得以切身经历来告诉大家,有时候,课本真的不一定是对的……

#include <fstream>
ifstream fin;
fin.open("uin_err_list");
int count=0;
string stUin;
while(getline(fin,strUin))
{
    count++;
    printf("data=%s\n",strUin.c_str());
}

这段代码有没有问题呢?没有~,基本上。《c++ primer plus》里都有的例子,怎么会有问题呢?
很遗憾,就是有问题。
当我在64位机器上启动这个程序的时候,总是在读取了第一行之后就自动结束,在检查了无数次未果之后,我不得不的出一个很无奈的结论---STL库对64位的支持有点差劲……

好啦,既然如此,那么我们就只能通过别的办法在64位机上循环获取数据,代码如下:

FILE * fp = fopen(file_qq, "r");
char data[100 ...

最后更新于 .

在代码编写中,我们经常需要用到int或者long等类型转化成特殊进制的字符串的问题,当然C里面提供了一些转义符来提供特殊进制输出,如%02x是输出16进制(只是针对一个char,08x是一个int),但是还是需要一个通用的函数来实现一个完整的功能比较好。

例如:转化成2进制

实际上就是每次右移一位,如果8进制就右移3位,16进制就右移4位,当然,mask也要对应更改。


//最左边是第一位
string ChangeTo2Left(unsigned long long flag)
{
string str="";
char temp[2];
unsigned long long mask = 1;
int tempFlag=0;
for(int i=0;i<64;++i)
{
tempFlag=(flag>>i) & mask;
snprintf(temp,sizeof(temp),"%d",tempFlag);
str.append(temp);
}
return str ...

最后更新于 .

转载自内部论坛,原文出处不明。

熟练使用gdb是一个linux下开发人员必备的一项技能,我们由浅入深的学习一下gdb的强大功能。
一.gdb简单介绍
名称

gdb - GNU 调试器

提要

gdb [-help] [-nx] [-q] [-batch] [-cd=dir] [-f] [-b bps]
        [-tty=dev] [-s symfile] [-e prog] [-se prog] [-c
        core] [-x cmds] [-d dir] [prog[core|procID]]

描述
    调试器(如GDB)的目的是允许你在程序运行时进入到某个程序内部去看看该程序在做什么,或者在该程序崩溃时它在做什么。

GDB主要可以做4大类事(加上一些其他的辅助工作),以帮助用户在程序运行过程中发现bug。
    o  启动您的程序,并列出可能会影响它运行的一些信息
    o  使您的程序在特定条件下停止下来
    ...

最后更新于 .

connect中使用了select模型,有如下地方需要注意:
我们提供的server api中有很多地方用到了select,特别是在等超时的时候,
例如:
fd_set recv_fds;
int iNum= 0;
if (m_iSocket <0) return -1;
FD_ZERO( &recv_fds );
FD_SET( m_iSocket, &recv_fds );
iNum= select( m_iSocket+1, &recv_fds, NULL, NULL, timeout );
return iNum;
这段代码对于cgi,或者简单的逻辑server不会有问题。但是对于多线程或者复杂的server可能会导致server core掉。
原因是select默认只支持1024个句柄,每个句柄采用和1024个bit对应的关系,如果fd的值超过1024,那么就会溢出。
也就是说,如果上面代码的m_iSocket>1024,那么后面的select就会溢出,即使只监听一个句柄也会溢出。奇怪的是select也不会报错。
而对于多线程或者大连接的server很有可能分配的fd超过1024.
所以建议以后写的api尽量有poll或者epoll的方式。
有poll改写了下面的代码:
int waittime = (timeout->tv_sec*1000)+(timeout->tv_usec/1000.0);
struct ...

最后更新于 .

     全头文件的C++库其实就是相关功能的定义与实现都包含在同一文件中,该类的调用者只需要include该文件即可,无需再将cpp加入到project中进行编译。而实现代码将直接编译到调用者的obj文件中,不再生成单独的obj,采用这种方式将大幅度减少调用 project中的cpp文件数与编译次数,只需“#include <xxx>”就可以使用类库的相应功能,不需要link到.lib/.a/.so/.dll等静/动态库。使用者方便,维护者省事,特别是对于一些轻量级的类库,因此非常适合用来编写公用的开源库。类似的例子有STL和boost中的一些组件以及正则库DEELX等等。     此种方式优点很多,但是编写中有以下几点要注意(以下假设hpp即为全头文件化的C++库的头文件):

    1、不可包含全局对象和全局函数。
    由于此种方式本质上是作为头文件被调用者include,所以当其中存在全局对象或者全局函数,而该文件被多个调用者include时,将在链接时导致符号重定义错误。要避免这种情况,需要去除全局对象,将全局函数封装为类的静态方法。
 
    2、类之间不可循环调用。
    在.h和.cpp的场景中,当两个类或者多个类之间有循环调用关系时,只要预先在头文件做被调用类的声明即可,如下:
   class B;
    class ...