Chinaunix

标题: 初中级C语言水平自测:srand((int)time(0)); 有没有错? [打印本页]

作者: pmerofc    时间: 2012-09-24 22:38
提示: 作者被禁止或删除 内容自动屏蔽
作者: bruceteen    时间: 2012-09-24 22:54
插科打诨的说,C语言中应该是NULL不是0吧
作者: pmerofc    时间: 2012-09-24 23:15
提示: 作者被禁止或删除 内容自动屏蔽
作者: zylthinking    时间: 2012-09-24 23:19
解毒专家莫非又在规定不允许隐性类型提升了?
作者: OwnWaterloo    时间: 2012-09-25 00:19
这能有什么(技术性的)错?

1. p = 0 与 p = NULL (假设p是指针类型)难道还会有区别不成?
只有在编译器不知道类型的情况下 —— 也就是省略原型与可变长参数 —— 它们在C中才会有区别。

并且这种情况下写NULL还不一定就是好习惯:
i) 写0在C或C++里都错
ii) 而写NULL在C++中肯定错,在C里依然不一定对 —— 我觉得这还不如前面的都错的结果。
iii) 只有(T*)0才是在C与C++中都对的写法。


2. 关于(int),写为(unsigned)或者干脆不写直接srand(time(0))也行。
time_t规定必须是算术类型 —— 也就是说不会像pthread_t那样存在被定义为结构体的可能性 —— 肯定能转换。
不进行错误处理,直接将(time_t)-1当作种子也是可以接受的结果。

剩余的可能的错误就是time_t是浮点并且time(0)的返回值超出了unsigned的可表示范围。。。
作者: pmerofc    时间: 2012-09-25 00:28
提示: 作者被禁止或删除 内容自动屏蔽
作者: zylthinking    时间: 2012-09-25 00:39
OwnWaterloo 发表于 2012-09-25 00:19
这能有什么(技术性的)错?

剩余的可能的错误就是time_t是浮点并且time(0)的返回值超出了unsigned的可表示范围


这也不是错, srand 本来就不期待一个确定的输入, 只要不发生内存访问违规, 就算是 'fuck' 也没人敢说是个错误, 你管他截取与否了

作者: OwnWaterloo    时间: 2012-09-25 01:00
回复 6# pmerofc

确实应该改为(unsigned)或者干脆不写转型。
每次看到pthread_create( ... , (void*)f, (void*)x , ... ) 这样的代码就感到无奈,这究竟是谁教的。。。
—— 也就是说应该这么做。


至于这么做的理由,要UB的话都是,怎么会一个是一个不是?

还有种子的问题,不一定会减少一半:

1. time_t -> int -> unsigned(srand的参数) 不一定就是 time_t -> unsigned 的一半
得看time_t的类型,还有time的返回值范围。


2. 即使只有一半
srand(i), i = [0, UINT_MAX/2) 对比 srand(i), i = [0, UINT_MAX],后者也不一定就会有更好的分布。
得看srand,rand是怎么实现的。


3. 哪怕将代码改为srand(0)(不仅仅是一半,而是UINT_MAX分之一),也不能肯定程序就一定是错的。
作者: pmerofc    时间: 2012-09-25 07:36
提示: 作者被禁止或删除 内容自动屏蔽
作者: mirnshi    时间: 2012-09-25 09:52
本帖最后由 mirnshi 于 2012-09-25 09:53 编辑

回复 8# OwnWaterloo

补充一些弹药:

在一些OS上time_t与机器位数有关,而且是signed的。32位上的就是int,64位的就是long.
在32位上对time()返回值做(int)只能说是没有任何意义。

srand()的参数是unsigned的,到了内部转换为u_long,作为随机种子。



作者: sonicling    时间: 2012-09-25 10:20
Should I use NULL or 0?
In C++, the definition of NULL is 0, so there is only an aesthetic difference. I prefer to avoid macros, so I use 0. Another problem with NULL is that people sometimes mistakenly believe that it is different from 0 and/or not an integer. In pre-standard code, NULL was/is sometimes defined to something unsuitable and therefore had/has to be avoided. That's less common these days.

If you have to name the null pointer, call it nullptr; that's what it's called in C++11. Then, "nullptr" will be a keyword.


转自 Bjarne Stroustrup's C++ Style and Technique FAQ
http://www.stroustrup.com/bs_faq2.html#null
作者: sonicling    时间: 2012-09-25 10:23
3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.


转自 C99 6.3.2.3 Pointers
作者: sonicling    时间: 2012-09-25 10:28
C++也有标准支持

C++2003
4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero. (略...)


C++11
4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t.


所有标准都支持 integer constant zero as null pointer。本人也习惯直接写0,而不是宏。
作者: starwing83    时间: 2012-09-25 21:20
回复 7# zylthinking


    我刚刚在Lua邮件列表看到了一个帖子:这的确是错,浮点转整型,如果超出了整型所能表示的范围,是UB,即如果time返回一个负的浮点值(额,这个可能性似乎不大),而转换成unsigned,那么就是UB。
作者: mirnshi    时间: 2012-09-25 21:30
starwing83 发表于 2012-09-25 21:20
回复 7# zylthinking


time_t不是浮点类型。
作者: starwing83    时间: 2012-09-25 21:32
回复 15# mirnshi


    我回复的是7楼,你仔细看看我们讨论的前提?
作者: mirnshi    时间: 2012-09-25 21:40
starwing83 发表于 2012-09-25 21:32
回复 15# mirnshi


原来在歪楼。
作者: zylthinking    时间: 2012-09-26 10:06
本帖最后由 zylthinking 于 2012-09-26 11:16 编辑
starwing83 发表于 2012-09-25 21:20
回复 7# zylthinking



你管他是不是 UB, 就算是 UB 怎么了, 会导致 srand 出错? srand 期待说我的参数必须是一个 非UB 的操作的结果???

似乎说的不是很清楚, 那么再说2句:
srand 只期待一个 sizeof(unsigned) 的数, 它并不管这个数是怎么来的, 就算他认为是 unsigned 的哪个数其实并不是 unsigned, 而是double, 或者任意值, 那也无妨, 解释成 unsigned 就是了。
srand 本身期待这个参数本就是一个任意值, 因此, 无论原来 double 之类专 unsigned 多么 UB, 只要能转换成功, srand 就获得了一个输入, 而且, 不管它的值是什么, 都是 srand 期待的。
要说有错误, 只有这种情况下有, 就是 time_t 不能转换成 int,  只要int 出来了, 神也阻止不了 int 变成 unsigned int
作者: starwing83    时间: 2012-09-26 11:41
回复 18# zylthinking


    你知道ub是什么意思么?就是任何事情都可能发生,可能直接返回0让你每次运行程序随机数都一样(苹果就这样),可能程序直接崩溃(访问了非法地址神马的),也可能烧cpu……UB的意思是一切皆有可能,程序是不能依赖UB行为的,这是常识你不知道???
作者: zylthinking    时间: 2012-09-26 11:56
starwing83 发表于 2012-09-26 11:41
回复 18# zylthinking

你知道ub是什么意思么?就是任何事情都可能发生,可能直接返回0让你每次运行程序随机数都一样(苹果就这样),可能程序直接崩溃(访问了非法地址神马的),也可能烧cpu……UB的意思是一切皆有可能,程序是不能依赖UB行为的,这是常识你不知道???


1. 我不知道还有能烧 CPU 的 UB, 我就知道有个能损害硬件的 CIH, 但那个是驱动级的病毒。
2. 莫非 srand(0) 就是错误么? 莫非会损害rand 的随机性? 只不过让伪随机数变得可预测, 给软件安全带来不稳定因素而已。 歪楼: 0 难道就是特殊值, 莫非静态调用 srand(2) 然后 rand 返回的就不可预测了???
3. 访问一个 time_t 莫非能崩溃??? 如果不能崩溃, 强制转换一个 time_t 会引起崩溃??? 你是不是觉得可能位数的不一致可能导致崩溃, 比如 time_t 是1位, 然后强制类型转换将后面的31位(假设)给占去了??? 如果是这样, 你是不是也认为 char c; int n = (int) c; 也会崩溃??? 歪楼: c 前的 (int) 是故意加的, 别象专家似的觉得拣了个宝。

作者: starwing83    时间: 2012-09-26 12:03
回复 20# zylthinking


    第一次见到依赖ub的程序员……

c专家编程里面有个例子,早期ibm机器上一个ub会烧掉显示器。

你知道什么是ub么?就是一切都可能发生,因为没有定义!怎么就不可能崩溃了?浮点数异常就不会蹦了?浮点数异常导致内核问题发生访问越界不可能了?ub就是一切都有可能。

还有,知道什么是错误么?不满需求的设计就是错误。本来一个随机迷宫,现在变成完全一致的不会变化的了,请问这都不是设计错误还有什么是错误???
作者: zylthinking    时间: 2012-09-26 12:06
starwing83 发表于 2012-09-26 12:03
回复 20# zylthinking

c专家编程里面有个例子,早期ibm机器上一个ub会烧掉显示器


将例子直接放在这里, 让我看看什么样的 UB 再不写 io ports 的情况下能烧硬件
什么都有可能是么, 我明白了 UB 是个框, 什么都能往里装
作者: zylthinking    时间: 2012-09-26 12:09
本帖最后由 zylthinking 于 2012-09-26 12:11 编辑
starwing83 发表于 2012-09-26 12:03
回复 20# zylthinking

还有,知道什么是错误么?不满需求的设计就是错误。本来一个随机迷宫,现在变成完全一致的不会变化的了,请问这都不是设计错误还有什么是错误???


既然要举具体例子, 那就更好办了, 我也具体呗, 找个平台架构出来, srand(time(0)) 能够产生出一个不变的迷宫出来
还有, 什么叫需求, 凭什么你给我附加一个随机迷宫的需求?
作者: zylthinking    时间: 2012-09-26 12:23
starwing83 发表于 2012-09-26 12:03
回复 20# zylthinking

浮点数异常就不会蹦了


好吧, 就假设 time_t 是浮点数了, 那么 ,
1。 time(0) 返回一个浮点数会不会异常?
2。 假设浮点数允许强行类型转换到整型,  (int) time_t 会不会浮点数异常???
3。 现在 srand 来了, 它接受一个整型, 和浮点数异常没关系

整体下来, 只有强制类型转换可能出什么浮点数异常, 那么强制类型转换是什么, 1。 要么不内存布局重排列直接重新解释, 2。 要么内存布局重排列, 然后按新类型解释。 第一种, 没有什么浮点异常, 只不过重新解释内存位, 第二种, 编译器负责转换格式, 再编译器控制内, 他可以出一个不可预测的整数值, 但会出现什么什么浮点数异常???

你在说什么浮点数异常时, 还是最好考虑一下, 到底能不能装在这个框里
作者: zylthinking    时间: 2012-09-26 12:32
starwing83 发表于 2012-09-26 12:03
回复 20# zylthinking

浮点数异常导致内核问题发生访问越界不可能了


这个看不懂, 既然你说可能了, 好吧, 你给我解释解释什么样的过程导致内核发生问题了, 其实我连内核会发生什么问题都不知道。 访问了非法地址么??? 怎么访问的, 怎么会访问呢? 既然是访问, 自然是指针相关, 指针在哪里???
作者: linux_c_py_php    时间: 2012-09-26 12:34
围观狗咬狗.
作者: newyorkumoney    时间: 2012-09-26 14:33
有错吗        
作者: KBTiller    时间: 2012-09-26 14:50
starwing83 发表于 2012-09-25 21:20
回复 7# zylthinking

    我刚刚在Lua邮件列表看到了一个帖子:这的确是错,浮点转整型,如果超出了整型所能表示的范围,是UB,即如果time返回一个负的浮点值(额,这个可能性似乎不大),而转换成unsigned,那么就是UB。


确实是这样
作者: OwnWaterloo    时间: 2012-09-27 15:45
标题: 《C专家编程》中毁硬件的例子
http://book.51cto.com/art/200803/68542.htm

未定义的行为在IBM PC中引起CPU瘫痪!

未定义的软件行为引起CPU瘫痪的说法并不像它乍听上去那样牵强。

IBM PC的显示器以显示控制芯片所提供的水平扫描速率工作。回扫变压器(flyback transformer,一种产生高电压的装置,用于加速电子以点亮显示器上的荧光物质)需要保持一个合理的频率。

然而在软件中,程序员有可能把视频芯片的扫描速率设置成零,这样就会产生一个恒定的电压输出到回归变压器的输入端。这就使它起了电阻器的作用,只是把电能转换成热能,而不是传送到屏幕。这会在数秒之内就把显示器烧毁,那就是未定义的软件行为会导致系统瘫痪的理由。


嗯,其实我没看出这与undefined behavior有什么关系。。。
作者: sacry    时间: 2012-09-27 15:55
回复 29# OwnWaterloo


    是想说UB可能会使scran rate变成0吧,大概。
作者: OwnWaterloo    时间: 2012-09-27 16:16
标题: 避免所有undefined behavior?
要避免所有undefined behavior并不容易。。。


@starwing83,既然Lua的邮件列表里提到了,我在想是不是因为Lua源代码里已经这么写了。。。
存在lua number -> c integral, 并且没有检查范围。

我估计很多需要大量处理浮点数的库,也不会对每一个long double -> double, double -> float 都进行检查。

并且。。。  请各位摸着良心说。。。  自己写的代码里有没有这样的情况:
1. 有符号数相加(或相乘!)
2. 相加前没有检测
3. 也没有去证明加法的结果一定没有超出该有符号数的表示范围


这也是undefined behavior:
C99 6.5 Expressions

5 If an exceptional condition occurs during the evaluation of an expression
(that is, if the result is not mathematically defined or not in the range of representable values for its type),
the behavior is undefined.

C89 6.3 EXPRESSIONS
...
If an exception occurs during the evaluation of an expression
(that is, if the result is not mathematically defined or not representable),
the behavior is undefined.
...


然后,在知道这是undefined behavior的情况下,不能再以无知者无罪为借口的情况下,会去将代码里的每一处有符号数加法都:
1. 证明它一定不会溢出
2. 或者在相加前检测
吗? 对检测失败的情况又该怎么处理?


我感觉这代价就太大了一些。。。  会开始考虑换 i) 有异常处理的 ii) 可以重载 + 的 语言了。。。
除0(mathematically defined)我想一般都会处理,因为一般都会立即产生错误。。。



回到srand(time(0))。不知道具体implementation的情况下, time_t有可能是浮点数, 也就有可能产生undefined behavior。
但如果一定要避免, 该怎么做?

  1. time_t t = time(0);
  2. if ( 0 <= t && t <= UINT_MAX ) srand(t);
  3. else { /* 该怎么办。。。 */ }
复制代码

  1. srand( fmod( fabs(time(0)) , UINT_MAX - 1 ) );
复制代码
不如前面那个罗嗦, 但依然很罗嗦。。。 而且不一定就没有问题。。。 (要是UINT_MAX-1 比 DBL_MAX 大该怎么办。。。 有这种可能性么?)


并且还得分两种情况: i) 这是实际代码,需要很好的正确性的保障(但这种情况srand/rand合适么?) ii) 这是教学代码并且主要目的、重点根本就不在srand/rand上。。。
如果这样写, 初学者看到了就不会对此有疑问?

@pmerofc,就类似 char const* , 严格的说应该这么写。
但有时候代码的重点不在这里, 需要避免一下子给初学者抛出太多的信息, 而是应该各个击破, 于是可能就先选择 char* 了。
你也理解的对吧?
作者: OwnWaterloo    时间: 2012-09-27 16:25
回复 30# sacry

但C语言并没有说scran rate为0是undefined behavior。
嗯,其实C语言里根本就不会有scran rate这个概念。。。


就是说,这个例子并没有说明是C语言里的undefined behavior(floating->integral超出范围、或者其他)造成硬件损坏的。
假设scran rate是一个特殊的内存地址,并且是算术类型。设置它的值为0在C语言里是正确的行为。
是这个硬件的spec不允许而造成的损坏。


不知道原文是什么。。。 也有可能是翻译出的问题。。。

作者: plp626    时间: 2012-09-27 16:42
回复 7# zylthinking


void srand(unsigned int seed);

这样会误导人吧。。。

传入参数是什么类型,由函数形参列表决定(窄转宽,或等宽转等宽),你传int后,它还是按照unisgned int “解读”。。。

作者: sacry    时间: 2012-09-27 17:19
回复 32# OwnWaterloo


    scran rate就是那什么什么扫描速率,

原文大概是这个,

http://books.google.co.jp/books? ... eltdown&f=false

我反复看都觉得这不象是某某已发事故,只是为了证明有这可能,“不是那么牵强”。
不是UB,我手滑把这东西设成0也会导致烧坏的..
作者: isaacxu    时间: 2012-09-27 17:40
这种用法真的很让人担忧,当初阿丽亚娜5升空后爆炸,其中一个导致发射失败的可能原因就是:64位的浮点数转为16位整型造成溢出。为此在C语言的安全规范中特别列出了这个问题。希望朋友们在实际工作中要特别小心这个问题。
阿丽亚娜5事故调查报告原文:The internal SRI software exception was caused during execution of a data conversion from 64-bit floating point to 16-bit signed integer value. The floating point number which was converted had a value greater than what could be represented by a 16-bit signed integer. This resulted in an Operand Error. The data conversion instructions (in Ada code) were not protected from causing an Operand Error, although other conversions of comparable variables in the same place in the code were protected.
作者: zylthinking    时间: 2012-09-27 17:45
isaacxu 发表于 2012-09-27 17:40
这种用法真的很让人担忧,当初阿丽亚娜5升空后爆炸,其中一个导致发射失败的可能原因就是:64位的浮点数转为 ...


要看具体情景, 你说的这个肯定是个  bug 无疑, 陈小三的交通灯例子里就不是。
不结合具体情况, 生搬教条, 做的再精确, 也失去了人的灵动, 干脆将大脑换成CPU好了, 也好让我尝试写个程序, 让他给我家打扫厕所
作者: OwnWaterloo    时间: 2012-09-27 18:05
回复 34# sacry

Great!

我勤快,弄个排字版:
Undefined Behavior Causes CPU Meltdown in IBM PC's!

The suggestion of undefined software behavior causing CPU meltdown isn't as farfetched as it first appears.
The original IBM PC monitor operated at a horizontal scan rate provided by the video controller chip. The flyback transformer (the gadget that produces the high voltage needed to accelerate the electrons to light up the phosphors on the monitor) relied on this being a reasonable frequency.
However, it was possible, in software, to set the video chip scan rate to zero, thus feeding a constant voltage into the primary side of the transformer. It then acted as a resistor, and dissipated its power as heat rather than transforming it up onto the screen. This burned the monitor out in seconds. Voilà: undefined software behavior causes system meltdown!


呃,观点还是前面的:
1. 这其实是在说"undefined software behavior", 以及与C语言的undefined behavior无关了
2. "set the video chip scan rate to zero" 的行为是良好定义的, 肯定能把它设置为0, 否则就不会烧毁了。
这段文字前面还有一段话:
since the behavior is undefined, the compiler is free to do anything and doesn't even have to warn you about it!

但设置为0, 编译器是必须老老实实做这件事的。


总之,C语言的undefined behavior引起严重事故的可能性不能说绝对没有。
但IBM的这个不能作为论据,它不是C语言的undefined behavior引起的,而且正是因为C语言是规规矩矩听了程序员的话、做了该做的事才会被烧毁的。。。
作者: OwnWaterloo    时间: 2012-09-27 18:10
回复 35# isaacxu

这个才有点C语言的undefined behavior引起事故的赶脚。。。
作者: madoldman    时间: 2012-09-27 18:39
回复 31# OwnWaterloo


    是的,这种溢出导致的UB,一定要避免,代码估计会搞得特别恶心。
我想起了java里没有unsigned类型,然后,某次要搞一堆的位运算,恶心死了。。。。
作者: captivated    时间: 2012-09-27 18:40
回复 37# OwnWaterloo


    速度来路过歪楼 顺便学习了
作者: isaacxu    时间: 2012-09-28 01:53
个人感觉还是要有事先的预防措施,今年黑帽大会上推荐的一本书叫"The Art of Software Security Assessment: Identifying and Preventing Software Vulnerabilities",书里介绍了C语言本身存在的安全问题,有兴趣的朋友可以翻一翻。
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. #include <limits.h>

  5. int main(void) {
  6.         int i;
  7.         float f1;

  8.         /* initialize fl */
  9.                 f1 = time(NULL);
  10.                   if (f1 > (float) INT_MAX || f1 < (float) INT_MIN) {
  11.                        /* Handle error */

  12.                    } else {
  13.                            /* Seed the random-number generator with current time so that
  14.                                       * the numbers will be different every time we run.
  15.                                       */
  16.                            srand( (int)time( 0 ) );//srand( (unsigned)time( NULL ) );
  17.                    }

  18.            /* Display 10 numbers. */
  19.            for( i = 0;   i < 10;i++ )
  20.               printf( "%6d\n", rand() );

  21.            return 0;
  22. }
复制代码

作者: 群雄逐鹿中原    时间: 2012-09-28 02:34
41楼代码自己写的吗?你这个有两个错误:

1. 可能导致srand未初始化。
    曾经碰到一个系统,srand未初始化,rand()每次返回一样的值,连随机数都出不来。

2. 两次time(0)返回的值可能不同,上一次不能作为判定依据


作者: isaacxu    时间: 2012-09-28 02:44
本帖最后由 isaacxu 于 2012-09-28 05:40 编辑

回复 42# 群雄逐鹿中原
烦请帮忙改改,因为要是直接用f1的话,随机种子就是定的了,再加上计算的方法不变,那下一次运行时的结果就会与上次相同。现在由于没有设定随机种子,那么在默认情况下随机种子来自系统时钟,二次运行的结果还是不同的。此外,现在这样也许能保证不会由于系统的问题导致溢出,但无法保证绝对不会溢出。
还麻烦告知可能出问题的系统,现在的程序只是在ubuntu12.04,Xubuntun12.04,Cloudera提供的ubuntu10.10,Win7四个系统下测试运行通过,其它许多系统下的运行情况都不太清楚,如能告知,万分感谢。


   
作者: pmerofc    时间: 2012-09-28 13:16
提示: 作者被禁止或删除 内容自动屏蔽
作者: isaacxu    时间: 2012-09-28 14:03
回复 44# pmerofc
试试这里


   
作者: pmerofc    时间: 2012-09-28 15:22
提示: 作者被禁止或删除 内容自动屏蔽
作者: 群雄逐鹿中原    时间: 2012-09-28 21:51
isaacxu 发表于 2012-09-28 02:44
回复 42# 群雄逐鹿中原
烦请帮忙改改


修改如下

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>

  4. int main(void) {
  5.     int i;

  6.     srand( time( 0 ) );

  7.     /* Display 10 numbers. */
  8.     for( i = 0;   i < 10;i++ )
  9.         printf( "%6d\n", rand() );

  10.     return 0;
  11. }
复制代码

作者: isaacxu    时间: 2012-09-28 22:37
回复 47# 群雄逐鹿中原
多谢指教


   
作者: captivated    时间: 2012-09-29 13:44
回复 18# zylthinking


    嗯, 这个我支持你的.

    UB UB, 管你怎么UB, C程序员至少还是能把握内存的. UB真恐怖到绝对的UB了, 艹, C语言不用混到今天了.

    不过我还是表示学习了,... 知道了浮点转整型如果超出range是UB而已. 溢出也是UB, 以前我从来没把溢出截断什么的当回事. 嗯, 好吧, 现在知道了, UB(弱弱地问截断也是UB吗哈哈, 比如int截断为short我可是从来都认为那是具有确定行为的东西, 这玩意应该不是UB罢? 这也是UB的话那我在标准派看来这些年又白混了...). UB那又怎么样, 拿本贴的例子来说, 你的说法我完全赞同.


作者: pmerofc    时间: 2012-09-29 14:02
提示: 作者被禁止或删除 内容自动屏蔽
作者: captivated    时间: 2012-09-29 14:09
本帖最后由 captivated 于 2012-09-29 14:11 编辑

回复 50# pmerofc


    嗯,专家回答下我的问题先,截断是UB吗(当然是指“正常且能成功的截断”,比如int类型变量截断为short(好吧,再加一个条件,假设知道了int类型变量是4个字节,而short类型变量是2个字节))。
作者: pmerofc    时间: 2012-09-29 14:15
提示: 作者被禁止或删除 内容自动屏蔽
作者: cdtits    时间: 2012-09-29 14:18
意义何在....
作者: captivated    时间: 2012-09-29 14:35
回复 52# pmerofc


    哦?那么就是说(设int 4 bytes, short 2 bytes),

    signed int i = 0x58ff823;
    signed short s;

    // 这个是UB? 我的理解从来就是直接截取低2个字节, 然后s的值为多少, 视内存布局解释的啊.
    s = i;

作者: pmerofc    时间: 2012-09-29 14:39
提示: 作者被禁止或删除 内容自动屏蔽
作者: starwing83    时间: 2012-09-29 14:42
回复 54# captivated


    说实话我以前经常这么写…………

看来得写成类似:

int j;
short i = (short)(unsigned short)j;

才行了……这又是何必呢……
作者: captivated    时间: 2012-09-29 14:43
回复 55# pmerofc


    そうか。了解了,TKS.
作者: captivated    时间: 2012-09-29 14:44
回复 56# starwing83


   
    哈, 那我还是把这个忘掉算啦。
作者: pmerofc    时间: 2012-09-29 14:45
提示: 作者被禁止或删除 内容自动屏蔽
作者: captivated    时间: 2012-09-29 14:46
回复 59# pmerofc


    吃地沟油的命,不敢操裆中央的心。
作者: isaacxu    时间: 2012-09-29 15:01
代码安全的问题早先主要是从事信息安全的人员比较关心,要让一般的开发人员认识到它的重要性,还需要一个过程但这是一个趋势。就ub而言,其实,标准里还是定义了一些ub的,只要大家留心不难注意到。比如,标准里6.5.5这一段就讲到了这个问题。原文:If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined。有时,ub的问题是编译器造成的,尽管开发人员做了处理,但编译器自作聪明将相关的校验代码给优化掉了。详细的可看这篇论文,论文的题目叫Undefined Behavior: What Happened to My Code? 里面涉及GCC 4.7、Clang 3.1以及在非X86下编译Linux内核、FreeBSD的随机函数等开源软件时出现的问题。
作者: starwing83    时间: 2012-09-29 15:48
回复 55# pmerofc


    这不是UB。

只有在源类型是浮点类型(from float pointing),而目标类型是有符号数(to signed integers)的时候,并且浮点截尾以后的数字超出了有符号数的范围时,才是UB。

其他的情况:如果目标类型是无符号整数,那就完事OK,行为有完全的定义。

如果目标类型是有符号整数而源类型不是浮点数,那么这个行为时实现定义的(implementation-defined)。

因此叔叔的那个操作不是未定义。
作者: pmerofc    时间: 2012-09-29 15:51
提示: 作者被禁止或删除 内容自动屏蔽
作者: starwing83    时间: 2012-09-29 15:57
回复 63# pmerofc


    看清楚了,上面说的是real floating type,叔叔的代码里面,右值是int,可不是什么real floating type呢。
作者: starwing83    时间: 2012-09-29 15:59
本帖最后由 starwing83 于 2012-09-29 15:59 编辑

就在你贴的那段英文的上面:
6.3.1.3  Signed and unsigned integers
1 When a value with integer type is converted to another integer type other than _Bool,if
the value can be represented by the new type, it is unchanged.
2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or
subtracting one more than the maximum value that can be represented in the new type
until the value is in the range of the new type.
49)
3 Otherwise, the new type is signed and the value cannot be represented in it; either the
result is implementation-defined or an implementation-defined signal is raised.

作者: pmerofc    时间: 2012-09-29 16:00
提示: 作者被禁止或删除 内容自动屏蔽
作者: starwing83    时间: 2012-09-29 16:01
回复 66# pmerofc


    恩,你记错了。只有浮点转有符号并且超出范围才是UB,整型转有符号超出范围是implementation-defined,剩下的都有定义。
作者: pmerofc    时间: 2012-09-29 16:02
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2012-09-29 16:08
提示: 作者被禁止或删除 内容自动屏蔽
作者: captivated    时间: 2012-09-29 18:38
回复 68# pmerofc


    了解了,不客气。
作者: captivated    时间: 2012-09-29 18:39
回复 62# starwing83


    哦, 谢谢~
作者: pmerofc    时间: 2012-09-29 18:41
提示: 作者被禁止或删除 内容自动屏蔽
作者: isaacxu    时间: 2012-09-29 19:03
本帖最后由 isaacxu 于 2012-09-29 20:33 编辑

按标准来肯定争议比较小,个人比较认同这样定义undefined behavior:Behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which the standard imposes no requirements. An example of undefined behavior is the behavior on integer overflow.此外,安全规范上列出来200多种ub的例子及其危险等级,删去这句(有些可能是标准里没有的)
作者: cdtits    时间: 2012-09-30 10:56
仔细看了看,感觉挺有意思
作者: isaacxu    时间: 2012-09-30 14:56
本帖最后由 isaacxu 于 2012-09-30 15:21 编辑

srand((int)time(0))这里面还是有讲究的,比如,随机种子是如何的设定,time是如何变化的。因此,使用时初学者要留心这些问题。删去了代码,因为里面可能有误。
作者: pmerofc    时间: 2012-10-13 19:04
提示: 作者被禁止或删除 内容自动屏蔽
作者: starwing83    时间: 2012-10-13 21:39
回复 76# pmerofc


    我提一点错误:0用在指针上下文中,就是空指针的意思,而且类型是对的(是什么指针上下文,就是什么类型指针)。NULL神马的只是口味问题而已。见这里:

http://oss.org.cn/kernel-book/ccfaq/node66.html
作者: pmerofc    时间: 2012-10-13 22:39
提示: 作者被禁止或删除 内容自动屏蔽
作者: sonicling    时间: 2012-10-13 23:18
回复 76# pmerofc


    有没有符号根本就没关系。time的返回值在2038年之前都不会溢出。2038年之后32位time()就不能用了。

srand根本就不影响随机性,随机序列的随机性由rand的实现决定,srand只不过重新开启一个随机序列罢了,只要每次给的值不同就行。

转换虽然是implementation-defined,但是不能跟着C标准一起想入非非。符号溢出会有signal吗?哪个平台是这么设计的?就算有,编译器也会警告你这种显而易见的严重影响效率的行为。






作者: sonicling    时间: 2012-10-13 23:21
本帖最后由 sonicling 于 2012-10-13 23:22 编辑

回复 76# pmerofc


    如果真的想你一样钻牛角尖的话,srand((unsigned)time(NULL)) 也是有*严重*问题的。

使用它的程序在两秒滴答间隔之内跑出来的值是一模一样的,一点都不随机!!!这严重影响了用户的使用,这个程序根本就不合格。语法再正确也没用。
作者: pmerofc    时间: 2012-10-13 23:53
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2012-10-14 00:00
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2012-10-14 00:02
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2012-10-14 00:06
提示: 作者被禁止或删除 内容自动屏蔽
作者: hbmhalley    时间: 2012-10-14 00:12
回复 84# pmerofc


    可能.太可能了.
作者: pmerofc    时间: 2012-10-14 00:20
提示: 作者被禁止或删除 内容自动屏蔽
作者: mirnshi    时间: 2012-10-14 01:07
回复 79# sonicling


只有32位系统存在2038问题,但随着64位的普及,这将不再是个问题,2038比千年虫问题要小很多。time之所以返回有符号,是因为用-1表示获取时间失败(没错,获取系统时间也会失败的,一切皆有可能)。在32位系统上time_t就是int型,转换成无符号,并不影响srand的功能实现。将time_t想象成浮点,只能是无知的表现。一群聪明的人设计出了生命力如此之长的OS,会脑残到用浮点表示秒数?time函数的岁数比坛子里很多人都大的。
作者: liuspring6    时间: 2012-10-14 01:15
pmerofc 发表于 2012-10-14 00:06
问题在于不可能在“两秒滴答间隔之内”运行程序两次,更不可能更多次


我记得time_t是以秒为单位吧,2次time调用得到一个值似乎有可能...
再说现在都是都多CPU、多核,在加上多线程,一个时间片上在2个核心上被执行完全不是难事
作者: starwing83    时间: 2012-10-14 01:16
回复 78# pmerofc


    pm,我个人觉得吧,这个语句本身其实没有这么严重的问题,要正视错误对不对?srand这个语句,严格意义上来说,除了(int)以外的问题都是口味问题,而(int)转换——实践上不影响,因为目前我见过的机器都是unsigned -> signed ->unsigned 会还原的。而我见过的编译器在不能还原的时候都会给警告的(xxx到yyy的转换可能损失精度)。退一万步说,就算不还原也无所谓,因为srand需要的值本来就是不要求是啥,最后,0和1原则上不属于Magic Number。

最后,我个人建议这一句着重说口味,说明一下各种口味问题,但是口味问题也不要有倾向!别说这句写的是错的——事实上,implementation-defined也不是错……
作者: hbmhalley    时间: 2012-10-14 01:19
本帖最后由 hbmhalley 于 2012-10-14 01:26 编辑

回复 84# pmerofc


   
问题在于不可能在“两秒滴答间隔之内”运行程序两次,更不可能更多次


    没看仔细
    不知道"秒滴答"是个啥单位 ..
    2个 滴答 间当然不现实 // why?
    但我确实因为time()单位是 秒 而被折腾过 ..
作者: sonicling    时间: 2012-10-14 01:46
回复 86# pmerofc


举个例子吧。

一个很简单的猜数字游戏(事先声明:没有输入检查,只说明问题,不做教学用途,别批我)
  1. #include <stdio.h>
  2. #include <time.h>

  3. int main(int argc, const char *argv[])
  4. {
  5.         srand(time(0));
  6.         if (argc == 2)
  7.         {
  8.                 int number = rand() % 100;
  9.                 int guess;
  10.                 sscanf(argv[1], "%d", &guess);
  11.                 printf("number=%d, you guess %d, you %s.\n",
  12.                         number, guess, number==guess?"won":"lost");
  13.         }
  14.         return 0;
  15. }
复制代码
自己猜太麻烦了,让电脑自己玩吧。
  1. #!/bin/sh

  2. for ((n=0; i<100; i=i+1)) do
  3.         ./rand $i
  4. done
复制代码
最后一定可以猜中一个,原因自己看:

[root@localhost test]# vi rand.c
[root@localhost test]# vi guess.sh
[root@localhost test]# chmod +x guess.sh
[root@localhost test]# ./guess.sh
number=38, you guess 1, you lost.
number=38, you guess 2, you lost.
number=38, you guess 3, you lost.
number=38, you guess 4, you lost.
number=38, you guess 5, you lost.
number=38, you guess 6, you lost.
number=38, you guess 7, you lost.
number=38, you guess 8, you lost.
number=38, you guess 9, you lost.
number=38, you guess 10, you lost.
number=38, you guess 11, you lost.
number=38, you guess 12, you lost.
number=38, you guess 13, you lost.
number=38, you guess 14, you lost.
number=38, you guess 15, you lost.
number=38, you guess 16, you lost.
number=38, you guess 17, you lost.
number=38, you guess 18, you lost.
number=38, you guess 19, you lost.
number=38, you guess 20, you lost.
number=38, you guess 21, you lost.
number=38, you guess 22, you lost.
number=38, you guess 23, you lost.
number=38, you guess 24, you lost.
number=38, you guess 25, you lost.
number=38, you guess 26, you lost.
number=38, you guess 27, you lost.
number=38, you guess 28, you lost.
number=38, you guess 29, you lost.
number=38, you guess 30, you lost.
number=38, you guess 31, you lost.
number=38, you guess 32, you lost.
number=38, you guess 33, you lost.
number=38, you guess 34, you lost.
number=38, you guess 35, you lost.
number=38, you guess 36, you lost.
number=38, you guess 37, you lost.
number=38, you guess 38, you won.
number=38, you guess 39, you lost.
number=38, you guess 40, you lost.
number=38, you guess 41, you lost.
number=38, you guess 42, you lost.
number=38, you guess 43, you lost.
number=38, you guess 44, you lost.
number=38, you guess 45, you lost.
number=38, you guess 46, you lost.
number=38, you guess 47, you lost.
number=38, you guess 48, you lost.
number=38, you guess 49, you lost.
number=38, you guess 50, you lost.
number=38, you guess 51, you lost.
number=38, you guess 52, you lost.
number=38, you guess 53, you lost.
number=38, you guess 54, you lost.
number=38, you guess 55, you lost.
number=38, you guess 56, you lost.
number=38, you guess 57, you lost.
number=38, you guess 58, you lost.
number=38, you guess 59, you lost.
number=38, you guess 60, you lost.
number=38, you guess 61, you lost.
number=38, you guess 62, you lost.
number=38, you guess 63, you lost.
number=38, you guess 64, you lost.
number=38, you guess 65, you lost.
number=38, you guess 66, you lost.
number=38, you guess 67, you lost.
number=38, you guess 68, you lost.
number=38, you guess 69, you lost.
number=38, you guess 70, you lost.
number=38, you guess 71, you lost.
number=38, you guess 72, you lost.
number=38, you guess 73, you lost.
number=38, you guess 74, you lost.
number=38, you guess 75, you lost.
number=38, you guess 76, you lost.
number=38, you guess 77, you lost.
number=78, you guess 78, you won.
number=78, you guess 79, you lost.
number=78, you guess 80, you lost.
number=78, you guess 81, you lost.
number=78, you guess 82, you lost.
number=78, you guess 83, you lost.
number=78, you guess 84, you lost.
number=78, you guess 85, you lost.
number=78, you guess 86, you lost.
number=78, you guess 87, you lost.
number=78, you guess 88, you lost.
number=78, you guess 89, you lost.
number=78, you guess 90, you lost.
number=78, you guess 91, you lost.
number=78, you guess 92, you lost.
number=78, you guess 93, you lost.
number=78, you guess 94, you lost.
number=78, you guess 95, you lost.
number=78, you guess 96, you lost.
number=78, you guess 97, you lost.
number=78, you guess 98, you lost.
number=78, you guess 99, you lost.
[root@localhost test]#


哎呀,居然跨越秒,还猜中两次,这运气真是好。
作者: sonicling    时间: 2012-10-14 01:48
刚好在秒滴答的时候猜中一次,这运气真的是逆天了!
作者: sonicling    时间: 2012-10-14 01:54
本帖最后由 sonicling 于 2012-10-14 01:55 编辑

我说错了一个地方,一旦跨越秒,就不一定能猜中。

玩了多次,绝大多数情况下都没有跨越秒,好不容易出现了一次都没猜中的情况:
  1. number=70, you guess 59, you lost.
  2. number=70, you guess 60, you lost.
  3. number=9, you guess 61, you lost.
  4. number=9, you guess 62, you lost.
复制代码
前后就不贴了。
作者: sonicling    时间: 2012-10-14 02:01
本帖最后由 sonicling 于 2012-10-14 02:08 编辑
pmerofc 发表于 2012-10-14 00:00
如果seed数目少,序列的数目也少(这个是我们的分歧之所在吧)


序列数目少一半也不是什么问题。40亿的一半也有20亿,总是用不完的。

Update:而且每个序列都是无穷的。

唯一的问题就是陈记错了srand的参数类型,还特地转换成int,结果画蛇添足了。
作者: gvim    时间: 2012-10-14 03:14
本帖最后由 gvim 于 2012-10-14 03:28 编辑

回复 82# pmerofc


少不了,现在的rand算法是 n = n * 16807 mod 2147483647 实现都只需要31bit就可以了,因为2^31 - 1 = 2147483647 是梅森素数,最适合32和64位系统(下一个是2^67-1)。另外rand的幻数16807选择需要能遍历1 --- 2^31-1之间的所有数,并且一个连续的遍历周期内只能出现一次(虽然16807遍历出来的数之间的相关性相比有些幻数不是最好)。
所以参数 n , 也就是种子给多了也没用,只要是32位和64位的机器,给不给符号不影响随机数的随机性也不影响产生的序列长度(超不出1 --- 2^31-1之间),或者哪怕产生了所谓的UB,也不影响随机性,这里随机性的来源是取时间的随机。种子的随机性导致rand结果的随机性才是使用rand的意义,而不是参数 n符号的 正确与否(因为错误不影响随机性)。

当然,这个话题当作转型,溢出,UB的讨论是成功的,呵呵。
作者: starwing83    时间: 2012-10-14 05:27
回复 94# sonicling


    我想知道seed少和数列少有什么关系………………

你给的是个unsigned,你哪怕给全0或者全1都能给你生成随机的数列,问题仅仅在于随机性不太一样。

如果seed非要达到多少bit的话,就不需要rand了,光seed自己的随机性就能保证一些应用了= =
作者: pmerofc    时间: 2012-10-14 08:21
提示: 作者被禁止或删除 内容自动屏蔽
作者: pmerofc    时间: 2012-10-14 08:28
提示: 作者被禁止或删除 内容自动屏蔽
作者: starwing83    时间: 2012-10-14 08:32
回复 97# pmerofc


    还是不对,因为srand的参数是unsigned,即使强制转换到int,也会最终转到unsigned,最终srand得到的数据量是一样多的。
作者: pmerofc    时间: 2012-10-14 08:35
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2