28
Apr

error C2653: ‘std’ : is not a class or namespace name

by huubby in C and CPP

Today, when I created a Win32 Console Application in VS2005, and wrote the code as follow:

#include “stdafx.h”

int _tmain(int argc, _TCHAR* argv[])
{
std::string    str = “”;
str += “helllo”;
str += “world”;

printf(“%s”, str);
return 0;
}

I got compile errors:

error C2653: ‘std’ : is not a class or namespace name

At the beginning, I thought it caused by a static library on which my new project depended. Then, I removed the static library dependent, but it didn’t work.

As you know, googling is a final solution when you find something you cann’t solve. I google it and figure it out. It’s simple, as MS has a bug in this situation.

You can find why this happend here, a relational situation about the issue is here.

Over!

19
Mar

restrict关键字

by huubby in C and CPP, Linux

看代码看到个restrict,头一次知道还有这么个关键字,在维基查到基本用法和解释。本着好记性不如烂笔头的原则,翻译这篇维基贴在这里。

在C语言的一个标准(C99)里,有一个用于修饰指针声明的关键字-restrict,它是程序员给编译器的一个意向声明,表明只有此指针或者基于此指针的某个值(比如 pointer+1)可以访问其指向的对象。这个关键字限制了指针别名(译注:即指向同一对象的不同指针),目的在于进行编译器优化。如果这个程序员没有遵守这个意向声明,并且这个对象由一个独立指针访问到的话,会造成未定义的行为。( 译注:我也没搞懂这一大段话什么意思 ^_^ 不过看下面的例子应该差不多能理解这个关键字的用法)

如果知道只有一个指针指向某个内存块的话,编译器就能进行优化,以生成更高效的代码。下面这个例子能清楚解释这一点。

void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *val)
{
    *ptrA += *val;
    *ptrB += *val;
}

这段代码里面,指针ptrA , ptrB, val可能指向同一块内存,所以编译器不能对代码进行优化。

load R1 ← *val  ; 加载val指针的
load R2 ← *ptrA ; 加载ptrA指针的值</pre>
add  R2 += R1   ; 相加
set  R2 → *ptrA ; 更新ptrA指针的值
; 对ptrB指针的操作类似,注意,这里val指针被加载两次,因为ptrA有可能和val指向同一块内存
load R1 ← *val
load R2 ← *ptrB
add  R2 += R1
set  R2 → *ptrB

如果使用restrict关键字,函数声明为:

void updatePtrs(size_t *restrict ptrA, size_t *restrict ptrB, size_t *restrict val);

编译器就能知道ptrA, ptrB, val三个指针指向不同的内存块,更新其中一个不会影响到其他的,从而对代码进行优化。当然,这里要由程序员保证这三个指针不指向同一块内存。

load R1 ← *val
load R2 ← *ptrA
add  R2 += R1
set  R2 → *ptrA
;编译器知道指针val的值没有改变,所以没有重新加载它,优化了汇编代码
load R2 ← *ptrB
add  R2 += R1
set  R2 → *ptrB

还有一个例子是memcpy函数,memcpy(void*, void*, nbytes)的前两个指针参数被声明为restrict,告诉编译器两个数据块没有重叠,便于进行优化,使得memcpy的速度更快。如果程序员用相同的指针作为这两个参数的值,那么memcpy函数会产生未定义的行为。
(译注:memcpy的前两个参数确实声明为restrict,但是用相同的指针做参数传进去测试,没发现异常行为,此处存疑。)

另:推荐一个专栏,M. Tim Jones 专栏,Linux 内核、虚拟化及其他技术深层剖析。(你可以在这个专栏中看到restrict的身影)

18
Mar

socket流程

by huubby in C and CPP

失败,准备写的东西放狗一搜总是一大筐,这次不写了,直接贴网上找来的图。

TCP方式的流程:


UDP方式:


15
Mar

linux编译生成动态库

by huubby in C and CPP, Linux

工作交接,手头没事闲的慌,试了一下怎么在Linux下生成动态库。放狗一搜,铺天盖地的文章讲这个(PS:这年头,好像所有的东西都有人介绍过)。随便点了篇照着试了一下,很容易就搞定。只是有一件事不太爽,最后一步测试的时候,我发现找不到生成的那个动态库,然后又觉得这个场景似曾相识。在记忆里google了一下,发现原来N天之前我已经试验过了,结果现在又全还给google。为避免下次继续出现这种情况,还是把自己的实验过程写出来,免得再还回去。

实验开始,先准备一个要封成动态库的类。

头文件:

//myclass.h
class CMyClass
{
public:
   int add(int x, int y);
};

实现:

//myclass.cpp
#include "myclass.h"

int CMyClass::add(int x, int y)
{
   return x + y;
}
把文件编译成.so动态库:  g++ myclass.cpp -fPIC -shared -o libmycls.so
OK,动态库有了,来看看怎么用。
//main.cpp

#include "myclass.h"
#include <iostream>
using namespace std;

int main(void)
{
    CMyClass mycls;
    cout<<"10 plus 3 is "<<mycls.add(10,3)<<endl;
}
编译main.cpp: g++ main.cpp -L. -lmycls -o main
看看生成的main能不能链接到我们的动态库:ldd main
如果像这样
linux-gate.so.1 =>  (0x005e5000)
libmycls.so => /home/user1/sourcecode/dlltest/libmycls.so (0x00ad8000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0039d000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0×00951000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00cdc000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0×00698000)
/lib/ld-linux.so.2 (0x00e12000)
第二行列出了之前创建的动态库,连接正常,执行main,看看结果吧。
附上-shared和-fPIC两个GCC选项的作用:
-fPIC:如果支持这种目标机,编译器就输出位置无关目标码.适用于动态连接(dynamic linking),即使分支需要大范围转移.
-shared:生成一个共享目标文件,他可以和其他目标文件连接产生可执行文件.只有部分系统支持该选项.
其实我在列出main的依赖项的时候碰到问题了,ldd main怎么也没列出来libmycls.so,后来设置环境变量才解决。打开~/.bashrc,增加两行($HOME是你的用户目录,$HOME/sourcecode/dlltest是动态库所在的目录):
LD_LIBRARY_PATH=$HOME/sourcecode/dlltest
export LD_LIBRARY_PATH
保存退出,在命令行里面输入:source ~/.bashrc,让刚添加的环境变量生效。再来一次ldd main吧,现在应该没问题了。