Archive for December, 2006

行业标准&潜规则–How to write solid and efficient code?(3)

题目四:
    
     其实这题是最简单的,就是int变量声明的顺序和空间分配的顺序,这里就应该是编译器的问题了。
对于不同的编译器可能出现下面两种情况:
    i    <–esp                k   <—esp
    j                或者        j
    k                             i
 
程序对于右边的情况当然是没有问题,但是左边的情况就会出现错误。
我在dev-c++和vs6上面c&r后发现都没有问题,在tc2上面就出现了问题,发现printf出来的结果不对。
如果把&k改为&i就ok了,呵呵,这个过程中我还犯了一个sb的错误,我尝试将memset中第二个arg改为1,
以为能显示出111,结果出了3个16843009,纳闷了半天,把这个数10to2换了一下发现是四个00000001,
恍然大悟memset是set char的。。。
 
题目五:
    
     地址对齐问题,不同的机器要求也不一样。x86/linux上,这个结果应该为8。结构体stru空间分配如下:
stru:
        .byte 65
        .byte 66
        .zero2      —-由于第一段4个字节段剩下2个byte放不下int,所以int对齐到下一段
        .int 10
        .ident     …..
     对于不同的系统,可以自己定义对齐数#pragma pack(push,n),强制以n字节对齐
 
题目六:
    
     对于一个老手而言,肯定会毫不犹豫的选择第二个,为什么呢?可能大多数人很少见或者没有见过第二种写法,
但在实际编程中第二种会避免你犯if(i=10)这种判断错误,因为if(10=i)编译器会报错,这样你就能发现错误。可能
大家会抱有一种无所谓的态度,说自己会注意不犯,相信我当你因为一个小错误而影响整个大的项目时,你就会明白
一种好的编程风格和习惯的重要性。
 
题目七:
    
     这个问题就和malloc&realloc有关系了。程序开始malloc了一个指针为p的1k空间(这里没有必要对malloc结果进行
强制转换),然后又以p开头扩大了1k空间,这中间没有必要free(p)因为realloc是对原空间的扩大。但是对于
void *realloc(void *memblock,size_t size);而言,1,memblock不为null,size==0,则memblock释放,返回null;
2,如果分配空间失败,memblock不变,返回null使p的值变为null,这样就不能对原来的空间进行free,造成内存泄漏。
最好这样,
char* temp=realloc(p,2048);
if(NULL==temp)
{
   free(p);
   return;
   …
}
 
题目八:
     这个很简单,数组是在函数运行期间,在函数空间内用堆栈存储的,随着函数的退出,堆栈被释放,返回一个指针也就
毫无意义了。但是如果不想在函数返回时,数组被pop掉,可以定义为static,也就是局部静态变量。
 
题目九:
     这个问题毛病挺多,首先大家可能都会想到数组越界,也就是对于str的缓冲区溢出,还有一个问题就是str是static,对
于调用这个函数的进程来说,它的生命周期是全局的,但是只能局部可见,所以在每次运行时,进行修改的都是第一次初始化
的static str,也就是对同一内存地址进行存取。为了避免static,而且还要能够返回str指针,当然就不能用数组了,可以考
虑使用malloc,这样内存分配在heap上,就不会释放了。问题例子:
 
#define MAX_STR_LEN 100
 
char *_strdup(const char *strSource)
{static char str[MAX_STR_LEN];
  strcpy(str,strSource);
  return str;
}
 
#include <stdio.h>
 
int main(void)
{
   char *c1
   char *c2;
   c1 = _strdup("micro");
   c2 = _strdup("stone");
 
   printf("%s%s",c1,c2);
   return 0;
}
这段代码可以看出程序修改的是同一地址。
我们来看看strdup生下来是什么样的。
char *strdup(char *s)                    
  {        
  char *__old=(s);  
  int __len   =   strlen(s);  
  char *__new=(char *)malloc(__len+1);  
  __new[__len]=”;  
  memcpy(__new,__old,__len);  
  return __new;   
好吧,把上面的问题程序重新写一下:
 
#define MAX_STR_LEN 100
#include <stdio.h>
 
char *_strdup(const char *s)
{
const char *_old=s;
int _len=strlen(s);
char *_new=(char *)malloc(_len+1);
_new[_len]=”;
memcpy(_new,_old,_len);
return _new;
}
 
int main(void)
{
   char *c1;
   char *c2;
   c1=_strdup("micro");
   c2=_strdup("stone");
   printf("%s%sn",c1,c2);
   system("pause");
   return 0;
}
 
题目十:
 
     fopen的参数不全,__try和__catch的匹配。。。
 
以上,over。

1 Comment

What is your perfect major?…

   so,我还是个数学天才.

You scored as Mathematics. You should be a Math major! Like Pythagoras, you are analytical, rational, and when are always ready to tackle the problem head-on!

Chemistry

75%

Mathematics

75%

Theater

67%

English

67%

Linguistics

67%

Engineering

67%

Dance

67%

Philosophy

58%

Psychology

50%

Art

42%

Journalism

33%

Sociology

33%

Biology

25%

Anthropology

17%

What is your Perfect Major? (PLEASE RATE ME!!<3)
created with QuizFarm.com

2 Comments

行业标准&潜规则– How to write solid and efficient code?(2)

Above All
寡人声明,这些内容都是寡人从网上收集的,目的就是做个3c(collection&compilation&combination),别tmd的说我copy。
First,逐个解决(1)中的问题
题目一:
 
1、选择f的理由
因为非NULL是约定,所以可以确定是调用者的问题,f可以明确地指出这一
点,防止错误扩散。防止错误扩散的意思是,如果用其他方式,比如throw
exception的方式,这个异常不一定会在调用此函数的上一层被捕捉到,可
能会被继续抛出直到最上一层或者直到在某一层被catch到,这样的话,错误
就会距离发生地点很远,扩散开来。

2、反对用f
不赞成assert, assert更重要的作用是程序体里面的一个注释, 在阅读程序
的时候起作用不能依赖他来检测错误, 很大程度上assert容易使使用者依赖
它本不应该依赖的东西。

3、另外一种观点
f和d都可取。如果没有系统开销的考虑,d则更好些。可以一举两得。如果没
人catch这个exception,其结果就跟f一样,按bug处理,dump core留下一
stack trace。如果有人catch,那就按运行错误处理……
但是返回一特初值表示错误,只是将错误上交,掩耳盗铃而已。最终总得有个
人assert,messagebox,throw exception,perror+exit,或别得什么的。既然已
经是约定,就干脆付起责任。

4、一种反对d的理由
不可用d, 这就像你用人,却不相信人一样,偏要try,catch防范他。其实那个错
是自己造成的,如果看到异常就容易不检讨自己。

5、关于观点3的支持意见
有人认为assert检查的是bug, 而异常是可以恢复的意外情况。
所以,观点3的支持者说:可恢复的意外是可以理解的,但可恢复的bug就没什
么意义了。既然已经约定好了,你再违背,就属于是bug而不是意外了(比如打
不开文件什么的)。很多库函数都不检查指针的合法性(除了系统调用以外,因
为总不能让系统dump core吧),也不检查指针是否为NULL(因为如果层层都检
查,必定劳民伤财,干脆让最上面调用的人在调用之外查)。

6、选择d+f
选f+d, 好处如下:
a以最激烈的方式,充分暴露调用都的错误!能及时修改BUG
b便于调试,问题出现后,直接到事故现场。比120还快!
c对于realse版的代码没有任何副作用。
d以处理的代价来看 采用断言也是编写最小一种。
e它是多语种,多平台所通用的方式, 如:C /C++ VB,Java在win ,unix
通吃, 便于移植!
如果在现实中,测试没有能找到所有的BUG,那可能就要用异常来帮忙了!
assert只在debug标志的时候有用,而在编译release版本的时候不起作用。
assert对于检查硬编码的错误,是非常有用的,能够及时的查处编码的错
误。比如borland c++的类库源代码中就有很多这样的assert。但是assert
不是万能的,因为有很多错误的发生不是完全在编译时发生的,而是运行
时的错误。在release后,assert是不可能依赖的。那么,我们就需要
exception这一机制来检测运行时错误,并相应的做出处理。当然,在异常
检测和处理过程中还有许多需要讨论的问题,由于不是这一题目的范围,
我们没有必要继续讨论得太多,但是,提出来希望大家注意:异常不是捕
获了就完成任务了,而要对于不同的情况,采取不同的处理办法,千万不
能只是捕获,而不做任何处理,那样和不捕获异常没有任何区别。

(a) if (!pParam)
return 0;
这是很多初级程序员常常采取的一种方式。返回值设为0。 因为函数的返回
值往往是计算的结果,不赞成把错误标志值和计算结果混在一起使用,容易
造成使用者的误会。当然,在很多unix函数中,由于历史原因,还存在很多这样子的函数,所以需要指出,不要沿用这种方式。

(b) if (!pParam)
return ERROR_PARAM;
b比a稍微好一点点,返回了一个常量或者预定义的宏。 从返回值的字面上,
调用者能知道发生了什么错误,但是,这也不是一种好的方法。
(c) if (!pParam)
pParam = "";

这是最不好的方式。直接给pParam赋予空字符串,然后继续函数过程,这
容易造成不可预料的后果,是程序不稳定的根源。
(d) if (!pParam)
throw EXCEPTION_ERROR_PARAM;
抛出异常,刚刚已经讨论过了,不再赘述。
(e) if (!pParam)
MessageBox(…);
这是一种比较可笑的方式,当然也有不少人用。MessageBox是直接弹出一个
对话框,告诉使用者,出错了。但是并不做任何处理,程序继续往下执行,
直到出错崩溃。呵呵
(f) assert(!pParam);
断言,刚刚已经讨论过了,不再赘述。

编写优质无错代码的经验:
a.理想的编译器和实际的编译器
b.使用断言
c.函数的界面设计
d.考虑风险
e.态度的问题

理想的编译器和实际的编译器:
a.把屡次出错的合法的C习惯用法看成程序中的错误
b.增强编译器的警告级别
c.使用其它的工具来检查代码 如 Lint 等
d.进行单元测试
e.消除程序错误的最好方法是尽可能早、尽可能容易地发现错误,要寻求费力最小的自动查错的方法
f.努力减少程序员查错所需的技巧
题目二:
a.该函数检查ch是否在A..Z之间,如果是,则返回相应的小写字符,如果
不是,则返回-1。
缺点在于:把错误标志值和计算结果混在一起使用,容易造成使用者的误会。
b.该函数使用了断言,如果ch在A..Z之间则返回相应的小写字符,如果不是,
断言会起作用,程序发生错误并退出。而最后一个return ch;则是在
release的时候,如果不是A..Z之间,则返回原来的字符。但是,从书写效
率上来说,这个函数稍微罗嗦了一点。因为它重复使用了断言和if判断。

c.该函数也使用了断言,返回相应大写字母的小写字母。

使用断言的好处:
a.暴露了调用者的错误
b.便于调试
c.对代码没有代价
d.最少的处理代价

断言使用举例:
void memcpy(void * pvTo,void *pvFrom,size_t size){
void *pbTo= (byte *)pvTo;
void *pbFrom= (byte * pvFrom);
assert(pvTo !=NULL && pvFrom !=NULL);
assert(pbTo >= pbFrom +size’ ‘pbFrom >= pbTo+size);

}

使用断言的规则:
a.要使用断言对函数参数进行确认
b.要从程序中删去无定义的特性或者在程序中使 用断言来检查出无定义特性
的非法使用
c.不要浪费别人的时间-详细说明不清楚的断言
d.消除所做的隐式假定,或者利用检查其正确性
e.在进行防错性程序设计时,不要隐瞒错误
防错性程序设计虽然被誉为有较好的编码风格,但它却隐瞒了错误。
要记住,我们正在谈论的错误决不应该再发生,而对这些错所进行的安全处理
又编写无错代码变得更加困难
f.要利用不同的算法对程序的结果进行确认
g.不要等待错误发生,要使用初始检查程序

断言小结:
a.要同时维护交付和调试两个版本。封装交付的版本,应尽可能地使用调
试版本进行自动查错。
b.断言是进行调试检查的简单方法。要使用断言捕捉不应该发生的非法情
况。不要混淆非法情况与错误情况之间的区别,后者是在最终产品中必须
处理的。
c.使用断言对函数的参数进行确认,并且在程序员使用了无定义的特性时
向程序员报警。涵数定义得越严格,确认其参数就越容易。
d.防错性程序设计会隐瞒错误。在进行防错编码时,如果”不可能发生”的
情况确实发生了,要使用断言进行报警。

 
题目三:
 
首先对memset()扫一下盲:
/*
  Sets the first "count" bytes of the memory starting at "dst" to the
  character value "val".
  For example:
  int *p;
  p=(int *)malloc(0x400*sizeof(int));
  memset(p,0,0×400);
*/
  void* memset(void *dst, int val,int count)
{
   byte* p=(byte*)dst;//void *p=dst;
   while(count–){
   *p++=b;//*(char *)dst=(char)val;dst=(char *)dst+1;
   }
   return dst;
}
int
main()
{
   char str[]="fuck9c";//这里
   memset(str,’x’,strlen(str));
   puts(str);
   system("pause");
   return 0;
}
这里还要说一些题外的东西,上面的char str[]为什么不能是char *str呢?
可以尝试一下用dev-c++ 4.9.9.2编译是通过的,但是运行时出现了错误报告,
用gdb r了一下发现是segment fault,why?
 
如下:
char *p="hello"不应该存在于今天的C++程序中了。
这种写法完全是为了保持对C中过去通行的(错误的)
写法的兼容性而对C++类型系统不得已的破坏。
不仅从原理上毫无道理,正如RoachCock所言,由p改写
"hello"会直接引发CPU异常。
此写法已被声明为deprecated,这意味着在未来的某一天
你的程序将不能通过编译。
in iso 2.13.4 string literal
item 1:
… An ordinary string literal has type "array of n const
char" and static storage duration…
item 2:
… The effect of attempting to modify a string literal is
undefined.
4.2 Array-to-pointer conversion
item 2:
A string literal … can be converted to an rvalue of type
"pointer to char": … [Note: this conversion if deprecated.
如果你新买的C/C++教材还在用这样的写法,应该立即把它扔掉。
可以这样理解:这句话
char* p="abc";
里的"abc"并非常量,而是以常量区的"abc"为源,在栈区里新申请的一个空间
虽然和书上的理论不符,但编译器是怎么做的就难说了
因为指向常量的指针不能够自动转换成不是指向常量的指针,反之则可以
—————————————————————–
我也觉得这个原因, 觉得VS2005的结果没有错.
编译器对语法的具体实现仁者见仁了。
GCC里输出为
foo( const char* )
catch( const char* )
指出一点:C++标准规定,字面字符串常量,像"abc",属于const char *。这一点是没有疑问的。但是现存的char *p = "hello,world",这样的代码太多了,如果严格按照标准来这种初始化是不能成立的,所以C++标准网开一面(还是为了向下兼容),特别允许这种语句合法。或者说,法外施恩来保证那些像楼主所说的char *到const char *的自动转换能够进行。但这不表明"abc"就是char *了,如果char *p = "abc",若试图修改p[0]就会引发一个段错误。关键在于"abc"存放于全局数据段。可以拿下面一个例子看:
#include <cstdio>
void f()
{
char *p = "abc";
std::printf("%pn",p);
}
int main()
{
char *p = "abc";
std::printf("%pn",p);
return 0;
}
运行一下看看,两个p指向的是同一个地址。之所以编译器能这样做,就是因为字符串常量是const char *,是一个imutable对象。虽然可以被转换为char *,但这样做无疑是有危险的。可以在上面的main函数里添加一个p[0] = ‘b’,马上会导致一个runtime error,如果是linux的话会告诉你是一个段错误。
指出一点:C++标准规定,字面字符串常量,像"abc",属于const char *。
----------
我觉得允许
char *p = "abc";
这样的声明有点误导人的意思,但是好像教材上都没提出过这一点
刚刚运行了下面这段程序:
int main()
{
const int a = 8;
int *p = const_cast<int*>(&a);
*p = 9;
cout << a << endl;
cout << *p << endl;
cout << &a << endl;
cout << p << endl;
return 0;
}
结果是:8, 9,0x12FF7C,0x12FF7C
虽然地址一样,但是a还是8,并没有象lz说的那样a会变成9
地址应该是0x0012FF7C,写掉了2位
好久没上C/C++板块,还是有一些很不错的讨论
收藏先
我觉得这并不是一个很大的错误/问题,就像guqst(pop) 说的,仁者见仁,智者见智罢了。
在编译器设计上差异而已,对于应用并没有很大的影响。
我有个同事说,CSDN上太学究了,差不多说得就是这吧?
我个人认为这不是一个bug,理由如下:
首先可以确定的是,"abc"这样的一个字符串确实是放在常量数据区的,我们可以在初始化的时候这样进行:char *p = "abc";
这时候p指向的地址和函数地址在数值上很接近,这说明p指向了代码区。
这样做的原因是为了向下兼容,因为C89上没有const的概念,所以很多初始化的时候都是这么调用的,如果C++不允许这么做的话,在移植方面就会出现很多的错误,导致C程序员不愿意将改用C++。这是C++语言为了生存所做的妥协。
那么如下的调用呢?char p[] = "abc";
这没有任何问题,首先你声明了一个数组,然后将数组的大小定义成刚好能存下"abc"字符串,并且就真的存放了"abc"在里面,这时你的数组数存放在数据区的,并且已经在数据区分配了相应的空间,不论是全局的也好,还是自动的也好。
C++还有一个规则就是,非常量指针可以隐式转换成常量指针,而反之则需要显示转换。如:
char a[10];
const char *p = a;
这是没有问题的,但这么做只是说当我用p来操作这个地址中的数据时,我只想进行读操作,这样做相当于编译器帮你做了一部分代码检查工作,防止你在用p操作地址时错误的修改了地址中的数据。但p指向的地址并不是在代码区,这和char *p = "abc"有很大的区别。
反过来:
const char *p = "abc";
char *a = p;
这是不允许的,需要进行转换:char *a = const_cast<const char*>p;
说明这是我想要的强制转换,但如果这时你调用a[0] = 1;这样的操作,还是不会成功。
既然我们都能理解foo(char*)和foo(const char*)是怎么共存的了,那么如果按照如下调用:
try
{
throw "abc";
}
catch (const char*)
{
cout << "catch(const char*)" << endl;
}
catch (char*)
{
cout << "catch(char*)" << endl;
}
抛出的异常将永远被const char*截获,由于char*可以隐式转换成const char*,所以编译器会通知说,有一段异常处理代码永远不会运行到。
如果我们如下调用:
try
{
char *p = "abc";
throw p;
}
catch (char*)
{
cout << "catch(char*)" << endl;
}
catch (const char*)
{
cout << "catch(const char*)" << endl;
}
增加一个指针的声明,我们就会发现,运行的效果是一样的。这就是为什么会让catch(char*)截获了的理由:
当异常抛出的时候,它首先走到了catch(char*)这个分之,它首先要进行初始化尝试,看是否可以将异常初始化成char*,由于以上所说,在初始化的时候,C++的编译器是允许将常量字符串赋值给一个非常量指针的,所以以上的异常将被第一个catch截获。
相同的例子:
foo(char *)
{
char *p = "abc";
}
当我们这么调用:foo("abc"),在函数调用时,不论是参数的传递,还是局部变量的初始化,都可以看作是存放在堆栈内的变量的初始化,所以常量字符串可以在初始化的时候传递给非常量字符串。
当然如下的声明更好:
foo(const char *)
{
const char *p = "abc";
}
const是编译器的一个关键字,用来限制对其后声明的变量的操作。
bcc 5.82 输出是:
foo( char* )
catch( char* )
 
好了好了,题外的东西有点太多了,还是回到题目中来,题目中的程序目的就是
想通过把多个字节合并为long型,然后写入内存来提高速度,其中longfill是用
"long"的值填充内存快,在填完了最后一个长字节之后返回一个指向下一次所要
填第一个长字的指针。结果速度的确提升了接近4倍。但是,程序忽略了两方面:
1,size初始值一定大于4么?
如果,size=3,程序就做了无谓的填充l,那么好了,我们这样:
 
void* memset(void *pv, byte b, size_t size) {
byte* pb = (byte*)pv;
if (size >= sizeThreshold) {
unsigned long l;
l = (b << 8) | b;
l = (l << 16) | l;
pb = (byte*)longfill((long*)pb,l,size/4);
size %= 4;
}
while (size– > 0) {
*pb++ = b;
}
return (pv);
}
我们可以设置一个threshold,来判断是否大于threshold再做下一步。
可是问题并没有结束:
2,long一定是4个字节么?
这一点程序没有做到,限制了其可移植性,于是我们再改:
 
void* memset(void *pv, byte b, size_t size) {
byte* pb = (byte*)pv;
if (size >= sizeThreshold) {
unsigned long l;
size_t Ssize;
l = 0;
for (Ssize= sizeof(long);Ssize–>0;)
l = (l<<8)|b;
pb = (byte*)longfill((long*)pb,l,size/Ssize);
size %= Ssize;
}
while (size– > 0) {
*pb++ = b;
}
return (pv);
}
ps:以上的做法在pv不是很大的情况下效率不一定就高。
 
 

1 Comment

行业标准&潜规则–How to write solid and efficient code?(1)

先弄点老题,如下:
题目1:
作为开发团队的一员,你需要实现一些库函数提供给其他人使用。假设你实
现的一个函数原型如下:

int DoSomeThing(char* pParam)
{

}

你们约定好参数pParam不能为NULL,但为了防止调用者错误传递NULL,你需
要在你的函数里做判断处理。
请问你会选择那种方式,并说明原因?

(a) if (!pParam)
return 0;

(b) if (!pParam)
return ERROR_PARAM;

(c) if (!pParam)
pParam = "";

(d) if (!pParam)
throw EXCEPTION_ERROR_PARAM;

(e) if (!pParam)
MessageBox(…);

(f) assert(!pParam);

 
题目二:
下面函数实现,哪一个好,为什么?
a.
char Uptolower(char ch){
if(ch >= ‘A’ && ch <= ‘Z’)
return ch+=‘a’-’A’;
return -1;
}
b.
char Uptolower(char ch){
assert(ch >= ‘A’ && ch <= ‘Z’);
if(ch >= ‘A’ && ch <= ‘Z’)
return ch+=‘a’-’A’;
return ch;
}
c.
char Uptolower(char ch){
assert(ch >= ‘A’ && ch <= ‘Z’);
return ch+(‘a’-’A’);
}
题目三:
下面的memset函数实现有什么问题?

void *memset(void *pv, byte b, size_t size)
{
byte *pb = (byte *)pv;
unsigned long l;
size_t sizeSize;

l = (b << 8) | b; /* 用4个字节拼成一个long */
l = (l << 16) | l;
pb = (byte *)longfill((long *)pb, l, size/4);
size = size % 4;

while (size– > 0)
*pb++ = b;
return (pv);
}

题目四:

下面的代码用memset将三个局部变量置为0,请问可能会有什么问题?
void DoSomeThing(…)
{
int i;
int j;
int k;

memset(&k, 0, 3*sizeof(int)); // 将i,j,k置为0

}

题目五:

定义结构如下:
typedef struct
{
char c1;
char c2;
int n;
} stru;
请问sizeof(stru)等于多少?并说明理由。

题目六:

下面是C语言中两种if语句判断方式。请问哪种写法更好?为什么?
int n;

if (n == 10) // 第一种判断方式
if (10 == n) // 第二种判断方式

题目七:

下面的代码有什么问题?
void DoSomeThing(…)
{
char* p;

p = malloc(1024); // 分配1K的空间
if (NULL == p)
return;

p = realloc(p, 2048); // 空间不够,重新分配到2K
if (NULL == p)
return;

}

题目八:

下面的代码有什么问题?
char *DoSomeThing(…)
{
char str[16];


return str;
}

题目九:
下面的代码有什么问题?

char *_strdup( const char *strSource )
{
static char str[MAX_STR_LEN];

strcpy(str, strSource);
return str;
}

题目十:

下面的代码有什么问题?并请给出正确的写法。
try{
FILE* fp = fopen("c:1.dat");
if (NULL != fp)
{

}
fclose(fp);
}
except(EXCEPTION_EXECUTE_HANDLER){
}

以上都是一些很老的题目了,再一次翻出来就是温故,知新就是奢望了

Leave a comment

最近很是无聊…

     等2.0等得要死,宅男的我没有事情做,只好无聊到开始研究programming,发现这门tech实在是侮辱我的智商,限制我的思维发散能力。为什么要遵循ANSI,做出来的东西都是从别人的模子里面出来的。也许你会说这是为了统一行业标准,提高效率,你还会说你个sb不遵循也可以,你喝西北风去吧。皑皑,我真是选错了专业,天生理论物理天才的我竟然跟风选了cs,还tmd跑到了tju。唉,仰天一声长叹,不说也罢,既然走到这里,就tmd把programming进行到底。

1 Comment

TMD,9C连个p都不放

看看人家tf最起码还有个公告,大陆这帮sb的经营理念阿,不从客户方面着想,还整个sb赏金活动,老子玩游戏是来happy的,不是tmd来挣你那点赏钱的。真的怒了,2.0不来,就将afk进行到底。
 
以下zz from tf:
 
     其实一切的纷争,都是因为公告后发生的状况
  相关单位会公告让大家知道,是因为要对玩家负责
  按照制式的回答:
  关于这个问题,请您注意官网公告

  但是相关的单位选择不这样做!
  所以就在预估知道会引起反弹的状况下,还是要跟大家说明

  在这边,希望能够先跟大家说明几点:

  首先,社群团队在与玩家在讨论版上面的互动上,似乎并没有强制删文或者删除讨论串的状况
  我们希望缔造的是能够相互沟通并且打破以往玩家与游戏公司的隔阂,我们一直自诩为超然的团队
  能够了解玩家所需,并且岃求与想法一而再的提出!!
  如果真的要控制大家发言,在这几天中,我们应该要暂时关闭这个讨论版才是 = =

  其次,台湾的玩家绝对不是次等公民,相信美方也不会这样想!
  不然,无须社群团队的产生,也不需要这个讨论版!
  美欧先行改版,而韩国在12/14也?陌?台湾应在其后会进行改版;
  并非部分玩家所说:韩国已经同步改版!!
  而韩国即他们也与玩家说明可能会发生许多的状况;
  而2.0.1的版本,与有问题的部份也几乎就是2.0.1最精采的部份
  在这样的前提下,当地提出了改版,而我们选择了等待!!
  希望大家了解,这并非擅自的决定经营;代理的公司,需要对全体玩家负责
  而我们不愿在更新之后,发生了状况,在与玩家说 抱歉,服务器的不稳定或一堆的问题
  是因为我们决定世界同步改版,所以影响了游戏的质量

  更完善的前置准备作业 语意不清引起大家猜测,
  我们对于这样的公告实感抱歉!
  其真正原因是大家所期待的资料片,有许多重大的变动
  而这些变动,会需要许多技术的支持!
  经营团队不愿意冒险在不确定因素下,而进行更新的想法,希望大家能够了解!

  我们到底何时可以更新2.0.1的版本?
  至少目前我这边是没有答案的,
  原因无他,需要继续观察2.0.1已经更新的国家后续状况
  而知道的答案是 这个问题目前被列入议题,且被关切中

  我们何时可以更新数据片的版本??
  这个…..我超期待,但会需要在2.0.1确定之后才能够得知
  并且,以日前美方的文稿显示,这会是在美欧改版后,韩国接着改版,之后是台湾与大陆!

  一但有最新的消息,社群团队会尽快跟大家说的!
  目前,我们举办了许多活动,希望能够让大家感到有趣,且在等待的过程中与我们同乐!!

1 Comment