博文

强制类型转换的错误(2012-03-02 15:09:00)

摘要:
今天遇到一个虚拟继承引起的类型转换错误,网上查到相关资料记录如下:
class VirtualBase { public: virtual class Derived* asDerived() = 0; }; class Derived : virtual public VirtualBase { public: virtual Derived* asDerived(); }; Derived* Derived::asDerived() { return this; } void main() { Derived d; Derived* dp = 0; VirtualBase* vp = (VirtualBase*)&d; dp = (Derived*)vp; // ERROR! Cast from virtual base class pointer   dp = vp->asDerived(); // OK! Cast in function asDerived }
   Virtual base classes give rise to other type conversion problems. It is possible to convert a pointer, to an instance of a class which has a virtual base class, to a pointer to an object of that virtual base class. The opposite conversion is not allowed, i.e. the type conversion is not reversible. For this reason, we do not recommend the conversion of a......

阅读全文(1644) | 评论:0

const引用和非const引用的一个区别(2011-05-07 13:43:00)

摘要:今天在一个网站上(http://www.cppblog.com/kongque/archive/2010/12/20/137036.html)看到一篇文章,记录下来。 原帖: 各位请看下面的代码  1 struct A {};
 2 
 3 struct B
 4 {
 5 public:
 6     B(){}
 7     B(A& a){}
 8 };
 9 
10 struct B1 : public B
11 {
12 public:
13     B1(const B& b) : B(b)
14     {}
15 };
16 
17 int main()
18 {
19     A a;
20     B1 b1(a);
21 
22     return 0;
23 }
上面的代码可以编译通过(gcc和vs2005下均测试通过),但是如果我将第13行的const修饰符去掉,编译就不能通过,报错说没有匹配的函数,请问各位高手这是为什么?望指教。
......

阅读全文(3598) | 评论:0

Intel体系MMX指令&指令说明(2011-05-06 23:34:00)

摘要:EMMS
MMX状态置空:
将FP特征字置空(全1),使后续浮点指令可以使用浮点寄存器,其他MMX指令自动置FP为全0.本指令应在所有MMX例程结束和调用可含有FP指令的例程时使用,以清除MMX状态. MOVD mm,r/m32
MOVD r/m32,mm 转移32位数据:
将32位数据从整型寄存器/内存移到MMX寄存器,和反向移动.MOVD不能在MMX寄存器之间,内存之间及整型寄存器之间移动数据.目标操作数为MMX寄存器时,32位源操作数写入目标寄存器的低32位.目标寄存器"0扩展"为64位.源操作数为MMX寄存器时,该寄存器的低32位被写入目标操作数. MOVQ mm,r/m64
MOVQ r.m64,mm 转移64位数据:
将64位数据从整型寄存器/内存移到MMX寄存器,和反向移动.目标操作数和源操作数可为MMX寄存器,64位内存操作数.但MOVQ不能在内存和内存之间进行数据转移. PACKSSWB mm,mm/m64
PACKSSDW mm,mm/m64 有符号饱和方式数据成组:
将MMX寄存器和MMX寄存器/内存单元中的有符号字组变成MMX寄存器的有符号字节组.和将MMX寄存器和MMX寄存器/内存单元中的有符号双字组变成MMX寄存器的有符号字组.(注1) PACKUSWB mm,mm/m64 无符号饱和方式数据成组
将MMX寄存器和MMX寄存器/内存单元中的有符号字组变成MMX寄存器的无符号字节组.(注1) PADDB mm,mm/m64
PADDW mm,mm/m64
PADDD mm,mm/m64 环绕方式数据组相加:
按环绕方式将MMX寄存器/内存单元中的字节组(字组,双字组)相加到MMX寄存器中(注1) PADDSB mm,mm/m64
PADDSW mm,mm/m64 饱和方式有符号数据组相加:
按饱和方式将MMX寄存器/内存单元中的有符号字节组(字组)相加到MMX寄存器中的有符号字节组(字组)数据.(注1) PADDUSB mm,mm/m64
PADDUSW mm,mm......

阅读全文(1590) | 评论:0

函数的调用约定(2010-12-10 12:07:00)

摘要: Using Win32 calling conventions 原文在这里:http://www.unixwiz.net/techtips/win32-callconv.html#decor 下面只是为了防止上面网页打不开而做的简单拷贝,文字未经排版,看起来很不舒服。请尽量使用以上链接查看   When writing code for the Win32 platform, most developers don't pay attention to selecting a "calling convention", and in most cases it doesn't really matter much. But as systems get larger and split into more modules (especially when third-party modules are to be included), this becomes something that cannot really be ignored.   In this Tech Tip, we discuss what the MSVC calling conventions are, why to choose one over the other, and "big system" considerations that may not be obvious.
Calling Conventions Traditionally, C function calls are made with the caller pushing some parameters onto the stack, calling the function, and then popping the stack to clean up those pushed arguments. /* example of __cdecl */ push arg1 push arg2 push arg3 call function add sp,12 // effectively "p......

阅读全文(4092) | 评论:2

C++标准学习之数组的初始化(2010-10-26 12:05:00)

摘要:实际应用中我们在定义一个数组的时候常常希望他能按照我们的想像初始化,比如: char buf1[10] = {0}; 这样写的目的我想大部分都是期望编译器会为每个元素自动初始化为0。测试一下发现基本上所有编译器也都是这么做的,但这么做“标准”吗? 或者说可靠吗? 看看标准中是怎么说的吧: 8.5.1 Aggregates 7.  If there are fewer initializers in the list than there are members in the aggregate, then each   member not explicitly initialized shall be value-initialized (8.5). [Example:
struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };
initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form
int(), that is, 0. ] 上面提到的 value-initialized 在8.5节给出了定义: To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class compon......

阅读全文(5439) | 评论:0

字符串内部查找函数(2009-01-20 10:36:00)

摘要:char* strchr( const char* str, int chr );
在str中查找第一次出现的chr,没找到则返回0 char* strrchr( const char* str, int chr );
在str中查找最后一次出现的chr,没找到则返回0 char* strstr( const char* str, const char* substr );
在str中查找第一次出现的substr,没找到则返回0 size_t strspn( const char* str, const char* chrset );
在str中查找第一个不包含在chrset中的字符的索引,即查找从str第一个字符开始的只包含chrset中字符的最长字符串字符数目
 strspn( "cabbage", "abc" ) == 5;
 strspn( "cabbage", "dc" ) == 1;
 strspn( "cabbage", "d" ) == 0;
 strspn("cabbage", "a") == 0;
 strspn( "cabbage", "" ) == 0;
 strspn( "cabbage", "\0" ) == 0;
 strspn("cabbage", "abceg" ) == 7;//返回str长度 char* strspnp( const char* str, const char* chrset );
和strspn功能一样,只是返回指针
const char* str = "cabbage"
strspnp( str, "abc" ) == str+5;
strspnp( str, "dc" ) == str+1;
strspnp( str, "d" ) == str+0;
strspnp( str, "abceg" ) == 0; // 和strspn不一样 size_t strcspn( const char* str, const char* chrset );
在str中查找第一次出现在chrset中的字符位置,没找到则返回str结尾的'......

阅读全文(5020) | 评论:0

虚函数原理的一个小例子(2008-11-20 18:12:00)

摘要:class A
{
    virtual void fun(){printf("this is a's private fun\n");}
};

class B
{
public:
    virtual void fun(){printf("this is b's public fun\n");}
};

int _tmain(int argc, _TCHAR* argv[])
{
    A* pa = new A;
    B* pb=(B*)pa;
    pb->fun();
    return 0;
} 对于pb->fun()编译器首先检查pb的类型为B,于是到B的定义里找fun发现是virtual。于是做了如下转换: typedef void (*pFoo)(); pFoo(*(int*)(*((int*)pb)))(); 这样起始调用的是A中的fun。 如果B的fun为虚,而A的fun非虚,编译器同样会做上面的转换,当然运行的时候就报内存访问违规了。原因很简单,A中并没有虚函数,自然不会有虚表。 如果B的fun是非virtual,编译器就编译器就直接调用了B中的fun: B::fun(); 这种调用最简单,因为不涉及虚函数,自然不会做类似上面的转换。......

阅读全文(3046) | 评论:0

如何取得结构变量的偏移地址(2008-11-19 10:42:00)

摘要:struct Foo{    int a;    char b;    short c; }; 如果我想观察编译器为了达到内存对齐的要求都在Foo的每个变量后加了多少padding字节,有什么办法? 我们知道编译器在定位一个成员变量的时候利用了2个信息: 1. 类对象的地址 2.将要访问的成员变量相对于类起始地址的偏移地址 这样编译器就可以通过 类对象的地址+成员变量的偏移地址 的简单计算得到成员变量在内存中的真正地址。 回到我们先头的问题,其实我们就是想知道第2个信息,即:将要访问的成员变量相对于类起始地址的偏移地址。 偏移地址的计算是编译器在编译该类的时候就已经确定的,因此应该有办法在编译期就得到这个值。考虑一般的调用情况: Foo foo; Foo *pfoo = &foo; pfoo->b;  //这一句编译器就将计算a的真正地址=pfoo的值+b的偏移地址。 那么如果pfoo的值为零,我们岂不是正好得到a的偏移地址吗?也就是 ((Foo*)0)->b我们能通过这样的形式获得我们想要的偏移地址吗? OK,运行一下... ... 发现运行期报了一个内存访问违规的异常(VC8),正常情况下,如果你的编译器没有什么问题,你都应该得到这个异常。仔细观察这个异常: Unhandled exception at 0x00411a06 in sss.exe: 0xC0000005: Access violation reading location 0x00000004. 啊?0x00000004不就是我们想要的偏移地址吗? 恍惚一下~~  发现自己犯了一个弱智的错误:我们不是要访问b的值,我们只是想得到他的偏移地址而已。把他的偏移地址当做他的内存地址当然会出错啦~~毕竟你的pfoo什么都不是(空指针)。 于是乎强制转换成地址:(int)((void*)(&(((Foo*)0)->c))) 这次输出正确了,就是4. 其实在stddef.h中有更加完整的定义,就是offsetof宏: #define offsetof(s,m)   (size_t)&reinterpret_ca......

阅读全文(4429) | 评论:0

视频与图像RGB/YUV格式详解(2008-10-12 14:05:00)

摘要:计算机彩色显示器显示色彩的原理与彩色电视机一样,都是采用R(Red)、G(Green)、B(Blue)相加混色的原理:通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。这种色彩的表示方法称为RGB色彩空间表示(它也是多媒体计算机技术中用得最多的一种色彩空间表示方法)。 根据三基色原理,任意一种色光F都可以用不同分量的R、G、B三色相加混合而成。   F = r [ R ] + g [ G ] + b [ B ]   其中,r、g、b分别为三基色参与混合的系数。当三基色分量都为0(最弱)时混合为黑色光;而当三基色分量都为k(最强)时混合为白色光。调整r、g、b三个系数的值,可以混合出介于黑色光和白色光之间的各种各样的色光。 那么YUV又从何而来呢?在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄像机进行摄像,然后把摄得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。 采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。 YUV与RGB相互转换的公式如下(RGB取值范围均为0-255):   Y = 0.299R + 0.587G + 0.114B U = -0.147R - 0.289G + 0.436B V = 0.615R - 0.515G - 0.100B   R = Y + 1.14V G = Y - 0.39U - 0.58V B = Y + 2.03U   在DirectShow中,常见的RGB格式有RGB1、RGB4、RGB8、RGB565、RGB555、RGB24、RGB32、ARGB32等;常见的YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、......

阅读全文(6024) | 评论:0

浮点数的存储格式(2008-06-27 11:59:00)

摘要:                                                   基于IEEE 754的浮点数存储格式            IEEE(Institute of Electrical and Electronics Engineers,电子电气工程师协会)在I985年制定的IEEE 754(IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Std 754-1985 )二进制浮点运算规范,是浮点运算部件事实上的工业标准。 1  浮点数     在计算机系统的发展过程中,曾经提出过多种方法表示实数,但是到目前为止使用最广泛的是浮点表示法。相对于定点数而言,浮点数利用指数使小数点的位置可以根据需要而上下浮动,从而可以灵活地表达更大范围的实数。     浮点数表示法利用科学计数法来表达实数。通常,将浮点数表示为 ± d.dd…d ×βe,其中d.dd… d 称为有效数字(significand),它具有 p 个数字(称p位有效数字精度),β为基数(Base),e为指数(Exponent),±表示实数的正负[1,2]。更精确地,± d0.d1d2…dp-1 × βe, 表示以下数  ±(d0+d1β-1+… +dp-1β-(p-1))βe,(0≤di<β)。     对实数的浮点表示仅作如上的规定是不够的,因为同一实数的浮点表示还不是唯一......

阅读全文(9015) | 评论:0