woaidongmao

文章均收录自他人博客,但不喜标题前加-[转贴],因其丑陋,见谅!~
随笔 - 1469, 文章 - 0, 评论 - 661, 引用 - 0
数据加载中……

static 变量初始化顺序引发的bug

没想到会遇到这样的问题,

在VC6环境下测试,重点请看红色字体与图片。

 

#include "stdafx.h"

#include <stdio.h>

 

typedef struct sData

{

    static const char* text;

    static int  val_a;

    static int  val_b;

} sData, *Self_Ptr;

 

typedef struct 

{

    char* text;

    int val_a;

    int val_b;

}* Other_Ptr;

 

 

const char* sData::text = "this is a test string\0";

int   sData::val_b = 200;

int   sData::val_a = 100;

 

int main(int argc, char* argv[])

{

    Self_Ptr p_self = (Self_Ptr)&(sData::text);

    Other_Ptr p_other = (Other_Ptr)&(sData::text);

    printf("%d\n", sizeof(sData));                          //----1, static成员不计入sizeof

    printf("val_a: %d-%d\n", p_self->val_a, sData::val_a);  //----val_a: 100-100

    printf("val_b: %d-%d\n", p_self->val_b, sData::val_b);  //----val_b: 200-200

    printf("val_a: %d-%d\n", p_self->val_a, p_other->val_a);//----val_a: 100-200

    printf("val_b: %d-%d\n", p_self->val_b, p_other->val_b);//----val_b: 200-100

    return 0;

}

 

image

posted on 2008-12-03 21:38 肥仔 阅读(3005) 评论(14)  编辑 收藏 引用 所属分类: C++ 基础

评论

# re: static 变量初始化顺序引发的bug  回复  更多评论   

这都什么啊……
类静态成员变量是链接进代码段的东西,同一个类中静态成员变量的地址没有谁向你保证过会连续的,三个变量三个完全不相干的地址都是完全合理的,你应该反思的是从一个静态成员地址反推其他静态成员地址这种完全不符合逻辑的做法。
另外,你的p_self->val_a之所以合法是因为它看的只是p_self的类型,编译的时候发现是静态成员就直接换成实际地址了。
你可以把
Self_Ptr p_self = (Self_Ptr)&(sData::text);
换成
Self_Ptr p_self = NULL;
结果是一样的。
2008-12-03 22:56 | RedNax

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@RedNax
如果我没有记错的话
class不是POD,即使是非静态成员,也不能保证连续,标准没有这样的规定。
成员为内置内型或POD类型且同时没有成员函数的struct可以归为POD了,标准规定POD内存必须连续,有static成员的struct还算不算POD,这个我倒是不知道。
2008-12-03 23:17 | 肥仔

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@RedNax
right, 你的判断正确,换成Self_Ptr p_self = NULL; p_self->val_a不会内存访问违规,说明编译期已经替换了p_self->val_a。
2008-12-03 23:38 | 肥仔

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@RedNax
根据你的提示,测试了另一个种情况,证明内存确实不连续,与定义顺序相关 +编译器相关。

我找到了一种强制内存连续的办法,接口转换也OK,但代码不好看了,如下:


#include "stdafx.h"
#include <stdio.h>

typedef struct
{
struct __Data
{
char* text;
int val_a;
int val_b;
} static data;

} sData, *Self_Ptr;

typedef struct
{
char* text;
int val_a;
int val_b;
}* Other_Ptr;

sData::__Data sData::data
={ "this is a test string\0", 100, 200};

int main(int argc, char* argv[])
{
Self_Ptr p_self = 0;
Other_Ptr p_other = (Other_Ptr)&(sData::data.text);
printf("%d\n", sizeof(sData));
printf("val_a: %d-%d\n", p_self->data.val_a, sData::data.val_a);
printf("val_b: %d-%d\n", p_self->data.val_b, sData::data.val_b);
printf("val_a: %d-%d\n", p_self->data.val_a, p_other->val_a);
printf("val_b: %d-%d\n", p_self->data.val_b, p_other->val_b);
return 0;
}
2008-12-04 00:03 | 肥仔

# re: static 变量初始化顺序引发的bug  回复  更多评论   

还是搞不懂你这样做是什么意思,要好看这样就可以了吧:

// #include "stdafx.h"
#include <stdio.h>


typedef struct
{
char* text;
int val_a;
int val_b;
}__Data, *Other_Ptr;

typedef struct sData
{
static __Data data;
} *Self_Ptr;

__Data sData::data
={ "this is a test string\0", 100, 200};

int main(int argc, char* argv[])
{
Self_Ptr p_self = 0;
Other_Ptr p_other = (Other_Ptr)&(sData::data);
printf("%d\n", sizeof(sData));
printf("val_a: %d-%d\n", p_self->data.val_a, sData::data.val_a);
printf("val_b: %d-%d\n", p_self->data.val_b, sData::data.val_b);
printf("val_a: %d-%d\n", p_self->data.val_a, p_other->val_a);
printf("val_b: %d-%d\n", p_self->data.val_b, p_other->val_b);
return 0;
}
2008-12-04 00:52 | RedNax

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@RedNax
?? 有差别吗? 代码不好看,我指p_self->data.val_a,多了一个data,能够去掉这个data就好看了。

因为项目中需要提供一个这样的能力:有几百个全部是static成员的struct,它们只有最后一个字段是个POD数组,长度会不同,需要有一个统一的接口来访问这些struct的成员,所以做了这个测试。

2008-12-04 10:35 | 肥仔

# re: static 变量初始化顺序引发的bug  回复  更多评论   

C++的意愿是希望大家不要太关注内存的布局,各个编译器的内存布局都是不太一样的。

标准规定POD内存必须连续
----------------------
C++标准吗?98年的时候和VC6一起出现,VC6能支持同一时期出现的标准?很明显不能。用VC6的话,就不要把C++标准扯嘴上了。
2008-12-04 11:47 | guest

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@guest
汗,VC6如果对POD这样的标准都支持不了,那就太那个。
VC6一直在用,而且最近1~2年内应该还是会作为工作的首选,没觉得有什么不好。赛扬CPU,512MB的内存,开4个VC6 IDE,并行开发一点都不卡,舒舒服服。
AMD双核,2G内存,打开一个VS 2008,只听到硬盘狂叫,10秒以上才能出个界面,这就是.net的效果?。
上次CSDN看到一个投票,目前C++集成开发环境,10年了的VC6占30%多,依然居第一位。



2008-12-04 12:19 | 肥仔

# re: static 变量初始化顺序引发的bug  回复  更多评论   

关于静态成员的引用,“p_self->val_a”这种写法虽然语法上没有问题,但是一般编译器都会直接认为是“sData::val_a”,所以肯定没有问题。
而“p_other->val_a”出现了问题,确实是因为内存有不连续的现象。static成员在运行时有可能是放到代码段里的,其具体规划很显然会受编译器和操作系统的影响;而一个普通的结构题变量实际上是连续的放在栈里的。
2008-12-04 13:21 | abettor

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@肥仔
代码里的问题和static变量初始化顺序没有关系...
编译器是编译器,编辑器是编辑器,虽然微软把他们绑成一个VC扔给博主,但博主最好还是把他们分清楚。喜欢VC6编辑器资源消耗小,没问题,你就一直用VC6的IDE写代码;喜欢VC 2008的编译器支持C++新标准,没问题,你就直接在在命令行用VC 2008的编译器编译就行了。不矛盾也不冲突。
2008-12-05 16:47 | helpsoff.com.cn

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@helpsoff.com.cn
呵呵,这不是我们第一次交流了,你这位同志比较喜欢好为人师嘛。但是需要说出点稍微有参考价值的东西,才可以教育别人,是不是。

交流需要平等,干嘛老摆个姿态呢,我觉得不好。
2008-12-05 18:44 | 肥仔

# re: static 变量初始化顺序引发的bug  回复  更多评论   

不知道博主又从那句话看出来本人好为人师了?我说话一直就是这个样子,你要是不喜欢,觉得我说的话没有参考价值,都是P话,尽管删了好了,反正这是你的地盘。

说实话,上篇文章看你做把ASSERT和if绑在一起的傻事,自己把网页一关就算了,管我P事。可偏偏又觉得不指出来,看着别人以做傻事为荣看不下去,结果好了,倒给博主卯上了。对我提了建议不入耳不说,还扣个帽子“摆姿态”。心想算了,多一事不如少一事。今天转博客又转到这里,看到这篇莫名其妙的代码再加上对VC的偏见,气又不打一出来。好吧,写两句说说。博主又说没参考意义,再扣个帽子“好为人师”。博主,既然你觉得我们是在交流,请拿出你对我留言的看法来先,技术层面上的,不要先对人打上标记带上偏见,好吗?

回到我上一条留言,我想问问你,你真的弄清楚,装完VC后,哪块是编辑器,哪块是编译器链接器,哪块是开发包了吗?
2008-12-05 19:33 | helpsoff.com.cn

# re: static 变量初始化顺序引发的bug  回复  更多评论   

@helpsoff.com.cn
呵呵,好了。

我必须得承认,你很强,你问的问题让我不知所措,我非常地茫然,几乎无地自容。当然不会删你的留言,只要不是粗痞话,我都不会删。大侠的更要留着偶尔看看,好让自己感到自卑。

这既然是一个你不屑的地方,就不必再来了吧,何必来看这么肤浅的文章影响了您老人家的心情?

送客了,远方的客人请您别再来~~~,:)


2008-12-05 21:00 | 肥仔

# re: static 变量初始化顺序引发的bug[未登录]  回复  更多评论   

。。。。。。。。。。。
路过。。。。。。。。。
。。。。。。。。。。。
2008-12-07 11:22 | cppexplore

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理