Posted in: 生活

C 语言仅凭自学能到什么高度?

头图

先来测测你现在的 C 语言水平怎么样…

假如现在你去一家公司面试,要求:定义一个宏,求两个数中的最大数

此处不要再往下看,停顿 5 分钟,写出你的答案,然后跟后面的答案对比。

———– 停顿 5 分钟 ————————————

合格

对于学过 C 语言的同学,写出这个宏基本上不是什么难事,使用条件运算符就能完成:

#define  MAX(x,y)  x > y ? x : y

这是最基本的 C 语言语法,如果连这个也写不出来,估计场面会比较尴尬。面试官为了缓解尴尬,一般会对你说:小伙子,你很棒,回去等消息吧,有消息,我们会通知你!这时候,你应该明白:不用再等了,赶紧把这篇文章看完,接着面下家。这个宏能写出来,也不要觉得你很牛 X,因为这只能说明你有了 C 语言的基础,但还有很大的进步空间。比如,我们写一个程序,验证一下我们定义的宏是否正确:

#define MAX(x,y) x > y ? x : y
int main(void)
{
    printf("max=%d",MAX(1,2));
    printf("max=%d",MAX(2,1));
    printf("max=%d",MAX(2,2));
    printf("max=%d",MAX(1!=1,1!=2));
    return 0;
}

测试程序么,我们肯定要把各种可能出现的情况都测一遍。这不,测试第 4 行语句,当宏的参数是一个表达式,发现实际运行结果为 max=0,跟我们预期结果 max=1 不一样。这是因为,宏展开后,就变成了这个样子:

printf("max=%d",1!=1>1!=2?1!=1:1!=2);

因为比较运算符 > 的优先级为 6,大于 !=(优先级为 7),所以展开的表达式,运算顺序发生了改变,结果就跟我们的预期不一样了。为了避免这种展开错误,我们可以给宏的参数加一个小括号()来防止展开后,表达式的运算顺序发生变化。这样的宏才能算一个合格的宏:

#define MAX(x,y) (x) > (y) ? (x) : (y)

中等

上面的宏,只能算合格,但还是存在漏洞。比如,我们使用下面的代码测试:

#define MAX(x,y) (x) > (y) ? (x) : (y)
int main(void)
{
    printf("max=%d",3 + MAX(1,2));
    return 0;
}

在程序中,我们打印表达式 3 + MAX(1, 2) 的值,预期结果应该是 5,但实际运行结果却是 1。我们展开后,发现同样有问题:

3 + (1) > (2) ? (1) : (2);

因为运算符 + 的优先级大于比较运算符 >,所以这个表达式就变为 4>2?1:2,最后结果为 1 也就见怪不怪了。此时我们应该继续修改这个宏:

#define MAX(x,y) ((x) > (y) ? (x) : (y))

使用小括号将宏定义包起来,这样就避免了当一个表达式同时含有宏定义和其它高优先级运算符时,破坏整个表达式的运算顺序。如果你能写到这一步,说明你比前面那个面试合格的同学强,前面那个同学已经回去等消息了,我们接着面试下一轮。

良好

上面的宏,虽然解决了运算符优先级带来的问题,但是仍存在一定的漏洞。比如,我们使用下面的测试程序来测试我们定义的宏:

#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{
    int i = 2;
    int j = 6;
    printf("max=%d",MAX(i++,j++));
    return 0;
}

在程序中,我们定义两个变量 i 和 j,然后比较两个变量的大小,并作自增运算。实际运行结果发现 max = 7,而不是预期结果 max = 6。这是因为变量 i 和 j 在宏展开后,做了两次自增运算,导致打印出 i 的值为 7。

遇到这种情况,那该怎么办呢? 这时候,语句表达式就该上场了。我们可以使用语句表达式来定义这个宏,在语句表达式中定义两个临时变量,分别来暂储 i 和 j 的值,然后进行比较,这样就避免了两次自增、自减问题。

#define MAX(x,y)({     
    int _x = x;        
    int _y = y;        
    _x > _y ? _x : _y; 
})
int main(void)
{
    int i = 2;
    int j = 6;
    printf("max=%d",MAX(i++,j++));
    return 0;
}

在语句表达式中,我们定义了 2 个局部变量_x、_y 来存储宏参数 x 和 y 的值,然后使用 _x 和 _y 来比较大小,这样就避免了 i 和 j 带来的 2 次自增运算问题。

你能坚持到了这一关,并写出这样自带 BGM 的宏,面试官心里可能已经有了给你 offer 的意愿了。但此时此刻,千万不要骄傲!为了彻底打消面试官的心理顾虑,我们需要对这个宏继续优化。

优秀

在上面这个宏中,我们定义的两个临时变量数据类型是 int 型,只能比较两个整型的数据。那对于其它类型的数据,就需要重新再定义一个宏了,这样太麻烦了!我们可以基于上面的宏继续修改,让它可以支持任意类型的数据比较大小:

#define MAX(type,x,y)({     
    type _x = x;        
    type _y = y;        
    _x > _y ? _x : _y; 
})
int main(void)
{
    int i = 2;
    int j = 6;
    printf("max=%dn",MAX(int,i++,j++));
    printf("max=%fn",MAX(float,3.14,3.15));
    return 0;
}

在这个宏中,我们添加一个参数:type,用来指定临时变量 _x 和 _y 的类型。这样,我们在比较两个数的大小时,只要将 2 个数据的类型作为参数传给宏,就可以比较任意类型的数据了。如果你能在面试中,写出这样的宏,面试官肯定会非常高兴,他一般会跟你说:小伙子,稍等,待会 HR 会跟你谈待遇问题。

还能不能更牛逼?

如果你想薪水拿得高一点,待遇好一点,此时不应该骄傲,你应该大手一挥:且慢,我还可以更牛逼!

上面的宏定义中,我们增加了一个 type 类型参数,来兼容不同的数据类型,此时此刻,为了薪水,我们应该把这个也省去。如何做到?使用 typeof 就可以了,typeof 是 GNU C 新增的一个关键字,用来获取数据类型,我们不用传参进去,让 typeof 直接获取!

#define max(x, y) ({    
    typeof(x) _x = (x); 
    typeof(y) _y = (y); 
    (void) (&_x == &_y);
    _x > _y ? _x : _y; })

在这个宏定义中,使用了 typeof 关键字用来获取宏的两个参数类型。干货在(void) (&x == &y);这句话,简直是天才般的设计!一是用来给用户提示一个警告,对于不同类型的指针比较,编译器会给一个警告,提示两种数据类型不同;二是,当两个值比较,比较的结果没有用到,有些编译器可能会给出一个 warning,加个(void)后,就可以消除这个警告!

此刻,面试官看到你的这个宏,估计会倒吸一口气:乖乖,果然是后生可畏,这家伙比我还牛逼!你等着,HR 待会过来跟你谈薪水!恭喜你,拿到 offer 了!

打造一个趋近完美的宏

以上的宏解决了自增自减运算符 ++/– 带来的一系列问题。但也不是十全十美,通过与 @左江 的激情讨论,发现还是有漏洞:在宏内部的语句表达中,我们定义了 2 个临时变量 _x 和 _y 解决了 ++/– 带来的问题,但是也引入了一个新漏洞,比如当我们使用下面的代码时:

max(x, _x)

当宏展开后,第二个参数就与宏内部定义的临时变量同名了,这就影响宏最后的结果。因此,为了防止用户传入的参数跟宏内部的临时变量产生同名冲突,我们可以将宏内部的临时变量尽量定义得复杂一些,降低同名的概率,比如 Linux 内核中 max 宏的定义:

#define max(x, y) ({				
	typeof(x) _max1 = (x);			
	typeof(y) _max2 = (y);			
	(void) (&_max1 == &_max2);		
	_max1 > _max2 ? _max1 : _max2; })

在上面的宏定义中,虽然临时变量 _max1 和 max2 比我们上面的 _x 和 _y 好点,也只是更进一步降低跟用户的传参同名冲突的概率,但是还是不能完全杜绝。极端一点,我们可以把这两个变量定义得无比长、无比奇葩,只要不超过 C 标准规定以的标识符最大长度 j 就可以:

_____________tmp______________________for_______________________max______

再奇葩的程序员,再猪一样的队友,哪怕是团队毒瘤、代码杀手,估计也不会定义这样的变量吧!这样同名冲突的概率就大大降低了,但是还是不能完全杜绝,算是 Linux 内核的一个小漏洞吧。

还好,谢谢 @王云峰 提供的链接,下载新版本的 Linux 内核,发现已经堵住了这个漏洞:

#define __max(t1, t2, max1, max2, x, y) ({              
	t1 max1 = (x);                                  
	t2 max2 = (y);                                  
	(void) (&max1 == &max2);                        
	max1 < max2 ? max1 : max2; })

#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)

#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)

#define max(x, y)                                       
	__max(typeof(x), typeof(y),                     
	      __UNIQUE_ID(max1_), __UNIQUE_ID(max2_),   
	      x, y)

在新版的宏中,内部的临时变量不再由程序员自己定义,而是让编译器生成一个独一无二的变量,这样就避免了同名冲突的风险。宏__UNIQUE_ID 的作用就是生成了一个独一无二的变量,确保了临时变量的唯一性。关于它的使用,可以参考下面的文章,写的很好:

Linux kernel 中的 min 和 max 宏

是不是已经完美了?

新版本 Linux 内核堵住了临时变量可能带来的同名冲突的漏洞,但是是不是就完美了呢?还是不一定!针对 Linux 内核中宏的新版本,最近又引发各种争论,比如针对常量、变长数组问题等,看看他们提交的各种更新的版本吧:

Variable-length arrays and the max() messThe joy of max()

   #define __single_eval_max(t1, t2, max1, max2, x, y) ({	
 	t1 max1 = (x);					
 	t2 max2 = (y);					
 	(void) (&max1 == &max2);			
 	max1 > max2 ? max1 : max2; })

    #define __max(t1, t2, x, y)						
	__builtin_choose_expr(__builtin_constant_p(x) &&		
			      __builtin_constant_p(y),			
			      (t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y),	
			      __single_eval_max(t1, t2,			
						__UNIQUE_ID(max1_),	
						__UNIQUE_ID(max2_),	
						x, y))

    #define max(x, y)	__max(typeof(x), typeof(y), x, y)The joy of max()   #define __single_eval_max(t1, t2, max1, max2, x, y) ({	
 	t1 max1 = (x);					
 	t2 max2 = (y);					
 	(void) (&max1 == &max2);			
 	max1 > max2 ? max1 : max2; })

    #define __max(t1, t2, x, y)						
	__builtin_choose_expr(__builtin_constant_p(x) &&		
			      __builtin_constant_p(y),			
			      (t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y),	
			      __single_eval_max(t1, t2,			
						__UNIQUE_ID(max1_),	
						__UNIQUE_ID(max2_),	
						x, y))

    #define max(x, y)	__max(typeof(x), typeof(y), x, y)

还有这种更加复杂的 max 宏的实现:

  #define __typecheck(x, y) 
		(!!(sizeof((typeof(x)*)1 == (typeof(y)*)1)))

    #define __is_constant(x) 
	(sizeof(int) == sizeof(*(1 ? ((void*)((long)(x) * 0l)) : (int*)1)))

    #define __no_side_effects(x, y) 
		(__is_constant(x) && __is_constant(y))

    #define __safe_cmp(x, y) 
		(__typecheck(x, y) && __no_side_effects(x, y))

    #define __cmp(x, y, op)	((x) op (y) ? (x) : (y))

    #define __cmp_once(x, y, op) ({	
		typeof(x) __x = (x);	
		typeof(y) __y = (y);	
		__cmp(__x, __y, op); })

    #define __careful_cmp(x, y, op)			
		__builtin_choose_expr(__safe_cmp(x, y),	
				      __cmp(x, y, op), __cmp_once(x, y, op))
 
    #define max(x, y)	__careful_cmp(x, y, >)


小结:

上面以一个宏为例子,意在说明,对一门语言的掌握是永无止境的,就算你把当前所有的 C 语言知识点、编程技能都掌握了,C 语言也是不断更新的、C 标准也是不断更新变化的。编程技巧、编程技能也是不断进步的。

而自学往往是最有效的学习方法,但是前提是你要有好的学习资料、学习方法、学习目标,再加上刻意练习和实时反馈。否则,就是两眼一抹黑,不知道自己学得怎么样、学到什么水平了、学了有什么用、学得对不对。其实还有一种比较有效的学习方法,找个行业内的工程师带一带、参考优秀的书籍、教程学一学、再结合几个项目练一练,就知道什么该学、要学到什么程度,而且可以大大提高学习效率。

TIPS:

本文题所涉及到的 C 语言知识点:

  • 自增自减运算符
  • 宏定义
  • 预处理过程
  • 运算符的优先级与结合性
  • 语句表达式:({……})
  • GNU C 的扩展语法:typeof 关键字
  • 内建函数:__builtin_……
  • ……

———————————————————————–

2019.04.25 补充:

没想到帖子引来这么多人关注,评论也越来越变了味……

在此统一回复一下:

帖子的主题是 C 语言能学到什么高度?言外之意,就是你对 C 语言能掌握到什么程度。

  • 写个 for 循环都要翻书的刚入门小白?
  • 还是有万行编程经验的老鸟?
  • 还是深谙 C 语言各种陷阱与缺陷的高手?
  • 还是 C 语言专家?

什么是专家?各种资料上解释很多,一般就是在某一领域研究很深、或者说专业知识很全面,不仅横向知道某一领域的各个知识点,还要纵向上对发展过程、技术演变历史有所涉猎。个人觉得 C 语言专家也应如此,想到达专家级别,掌握 C 基本语法、编程技巧、写代码能力这是基础,更重要的是要知道:

  • 知晓 C 语言的各种陷阱与缺陷、如何写出稳定高效的代码
  • C 标准的掌握:它的发展过程、是如何演变的、解决了什么问题、弥补了 C 语言的哪些漏洞
  • 不同编译器厂商、行业对 C 语言的语法扩展:C51、ARM、GNU C 等
  • 一段相同的代码跨平台运行、在不同的编译器下运行,预期结果相同吗?为什么?
  • 以 C 语言作为工具媒介,掌握各种平台编译器特性、系统架构、软件工程、框架、算法…

尤其是在嵌入式、底层系统软件这种对性能要求极高的开发中,开发人员除了熟练使用 C 编程之外,还要深谙 C 语言的各种高级特性、语法扩展、编译器特性、体系架构、编译原理等,才能写出高效率、高性能、更加稳定灵活的系统软件。

本来想以模拟面试举例,来测试你对 C 语言的掌握到了什么程度,有哪些知识点没有掌握,就这么简单。面试跟考试一样,本来就是一个选拔、淘汰机制。你高考的 log 现在用了多少?你面试考得各种东西实际工作中又用了多少?这就跟我们校园里的石板路一样,合理不合理让学生的脚投票:你会发现有些路尽管设计得很漂亮,但是基本上没人走,一步娘炮、两步扯蛋。而有些草地上,自发形成了各种捷径,走得人多了,也就成了路…

技术本身就很枯燥,学习本来就是很反人性的,为了使文章生动活泼有趣点,就举了个面试的例子,顺便夹杂几个段子、活跃活跃气氛,结果就引来各种人身攻击,揪住段子不放,至于么……,之所以删除楼下某层的评论,你自己来干嘛的,你自己心里很清楚,就事论事,就技术本身进行讨论,这个帖子永远欢迎。一上来就人身攻击,把自己那点经验当做真理,拿来指教别人,开始人身攻击,你我了解多少,你就敢下这么多武断的结论?你写过多少内核代码?写过多少内核驱动?你觉得内核难,那是你的事情,比你厉害,比你牛的人多的是,想成为牛 X 的人也多的是,你不会,你觉得痛苦,但你不能打击别人,阻断别人前进、进步的道路。你作为老师,带给学生的是希望?还是一个你武断结论下的绝望?

至于你说的天分论:每个学生有自己的天分,不行趁早转行。严重不同意你的观点。能考上大学,大家的智商都差不多,资质水平说白了都差不多。为什么有的学生越来越优秀,为什么学生之间的差距越来越大。最主要的原因根本不在于智商、天分,而是自律的品格、坚持的毅力、成长型思维这些优秀的性格品质在起作用。从某个时间节点或短期来看,个体的差异可能导致每个人对某一个问题的理解和接受能力不同,但从长远来看,学习成绩、工作绩效、科研成果的好坏,绝不仅仅是天分决定的,而是毅力! 毅力把生活当成一场马拉松,而不是短跑。毅力是对未来的坚持、日复一日,是对长远目标的激情和坚持。随着时间的积累,人的学习能力也是会变化的,它会随着你的努力程度而变化。你作为老师,倒好,一句天分论,打倒学生一大片,你知道你扼杀了多少个可能吗?

刘国梁的闺女生下来就会打高尔夫?柯洁生下来就会下象棋?郎朗在娘胎里就会弹钢琴?不是的,他们都是经过刻意练习、努力锻炼的结果。教学方法、训练方法随着时间的推移和技术的进步,都是可以不断提高和完善的。孙杨、宁泽涛、苏炳添,这些不断刷新记录和突破自身极限的优秀运动员,也在不断尝试国外先进的训练方法、或者聘请国外优秀的教练。包括最近在看的电影《绝杀慕尼黑》,苏联佬都知道美帝的培训更加先进,引进来训练自己的学员并最终获得奥运冠军。IT 培训也是如此,行业早起,技术积累不足、行业经验积累不够,IT 培训可能仅仅是入门,让学员能够找到工作。但是随着技术的进步、行业项目经验的积累,IT 的训练方法、培训体系也会不断提高和完善的。你作为培训老师,如果还停留在引导初学者入门,“师傅领进门,修行在个人”这些传统的观念上,我觉得你并不是一个优秀的老师,作为培训老师,也要不断跟踪行业变化、不断完善训练方法,培养出更高水平的学员。

在行业发展早期,由于学习资料、技术积累、行业经验的不足,每一个技术高手可能要走过很多弯路、踩过很多坑、浪费很多时间、瞎折腾很长时间,才能把自己的技术水平提高到一个很高的水准上。但是随着技术的进步、技术门槛一点点地被攻破,后来者就不用走太多弯路,吸取前人经验,就可以相对轻松地达到较高的水准。作为老师,主要职责就是从行业经验、失败案例、大家踩过的坑中总结经验、形成新的训练方法和教学体系,进而培养出更高水平的学员。你作为老师,还抱着“师傅领进门,修行在个人”的思想,我觉得已经不太适宜这个时代了,也许你是对的,这个世界就是这样,有人想中庸,平平淡淡过日子,岁月静好,有人想追求极致,不断超越自己、不断突破自己的极限。你有你的生存空间和教学思想,但是你不能不允许像《爆裂鼓手》这样的老师和学生的存在。

因此把在帖子里宣称自己是老师的一些人身攻击的评论删除了,你自己单开一贴骂就可以了,不想再理你,祝您开心。只是想善意提醒一下,作为一名在知乎上到处宣称自己是老师,并在 B 站上兼职做游戏主播的您,如果不能分享有趣的知识给大家,建议还是全职做游戏主播比较靠谱,至少不用现在在知乎上到处蹭热点、举报这个、举报那个,还引以为豪,把自己举报的战绩挂到自己的空间里分享,您不觉得无聊么?这就是您作为一个老师的基本素质?如果您无聊的话,建议多分析几篇你引以为傲的 C 语言混乱代码,多实用啊!挂到自己的空间上,还可以装点门面。然后哄一帮小孩子编程,反正又不用到实际的工作项目中。我们现在讨论的是 C 语言在嵌入式、Linux 行业扎扎实实在用的一些东西,不学习就看不懂、影响工作的一些东西,总之,跟你不在一个频道上。您在外围既然不想踏进来,那就继续呆在你的舒适区,也请不要忽悠想进来进一步提高的人跟你一样在外围转悠。至于其他的您就别费心了,希望您在少儿编程领域越走越好,小孩子跟着你能开心,喊你一声叫哥哥,一下子又仿佛年轻好几岁,是不是很开心?岂不乐哉?

宏 VS 内联函数

关于宏和函数的讨论,这个一下子说不清楚,有很多历史遗留原因:早期的 C 编译器,由于编译环境限制,比如内存可能只有几十 KB,不能把一个工程的所有源文件都加载到内存一次性编译,而是一个文件一个文件的编译,然后再使用链接器链接,生成可执行文件。所以对于变量、函数名这些标识符,必须先声明后引用,以配合编译器检查,于是就有了头文件这个东西。

包括内联函数也是一样,内联函数的执行效率高,书写方便,易于维护。早期的 C 语言是没有内联的,后来的 C 语言标准借鉴了 C++ 的很多优点,才扩充成为自己的 C 语言标准,比如内联函数、支持 // 注释等。但在早期的 C 中,宏确实是个编写程序的利器,尤其是在一些 C 开源软件中,如 glibc、Linux 内核,到处可见其张牙舞爪、各种炫技。那些顶尖的内核开发者们似乎要把宏的极限发挥到极致,把 C 语言的性能在底层开发领域发挥到极致。

对于一个 C 语言初学者来说,这里只是拓展了你对 C 语言的认知上限和边界:原来 C 语言还有这些不被人熟悉的东西。如果你以后想从事互联网开发,以后学习 Java、python、PHP、C++…..,这些东西可以不必关心,因为以后也用不到。如果你以后从事嵌入式开发、Linux 环境下开发,可能会接触到很多底层代码、跨平台代码,C 语言的这些扩展语法、底层的一些特性还是不得不学的,因为这些底层代码、GNU 开源代码处处在使用它。

关于宏的进一步学习,可以参考下面这 2 个帖子,写得很好:宏的很多应用并不是装逼,而是能很优雅地解决很多实际问题:

代码自动生成 – 宏带来的奇技淫巧 – loop_in_codes – C++ 博客深入理解 C 语言中宏定义

这篇帖子是从我以前写的 C 语言教程《嵌入式 C 语言自我修养》1~13 篇中的一篇 copy 过来的。在自己从事驱动开发、阅读内核源码的学习和工作过程中,总感觉阅读 Linux 内核代码力不从心,有些代码稀奇古怪,很难理解。在此背景下写了这篇 GNU C 扩展语法教程,旨在帮助大家学习 Linux 环境下,C 语言的一些扩展的语法,突破阅读障碍。大家以后如果想从事 Linux 环境下的开发工作、包括 Linux 内核、系统开发、应用开发,甚至阅读一些 GNU 开源软件,这部教程对您还是有一定帮助的。对于 C 语言初学者来说,希望这篇文章能拓宽你的视野:C 语言不仅仅是书本上、教科书上的那些知识,还有一些书本上现在看不到的知识。本人时间精力有限,尝试写了一部分,希望能拓宽你的知识面,开拓你的视野。

你是继续停留在自己的舒适区,岁月静好?还是不断去拓展自己的知识边界,不断提升自己,不断去提高自己的职场竞争力?路在你的脚下,选择权在你的手中。

跟涛哥一起学嵌入式宅学部落:跟涛哥一起学嵌入式 15:你为什么看不懂 Linux 内核驱动源码?宅学部落:嵌入式 C 语言自我修养 01:Linux 内核中的 C 语言语法扩展宅学部落:嵌入式 C 语言自我修养 02:Linux 内核驱动中的指定初始化宅学部落:嵌入式 C 语言自我修养 03:宏构造利器:语句表达式宅学部落:嵌入式 C 语言自我修养 04:Linux 内核第一宏:container_of宅学部落:嵌入式 C 语言自我修养 05:零长度数组宅学部落:嵌入式 C 语言自我修养 06:U-boot 镜像自拷贝分析:section 属性宅学部落:嵌入式 C 语言自我修养 07:地址对齐那些事儿宅学部落:嵌入式 C 语言自我修养 08:变参函数的格式检查宅学部落:嵌入式 C 语言自我修养 09:链接过程中的强符号和弱符号宅学部落:嵌入式 C 语言自我修养 10:内联函数探究宅学部落:嵌入式 C 语言自我修养 11:有一种函数,叫内建函数宅学部落:嵌入式 C 语言自我修养 12:有一种宏,叫可变参数宏宅学部落:嵌入式 C 语言自我修养 13:C 语言习题测试

Posted in: 生活

将独立的「鸟纲」置于「恐龙总目-兽脚亚目」的分类下是否合理?以及翼龙与鸟类存在演化上的关系吗?

头图

鸟(Aves)——作为陆生羊膜类动物中种群数量居首的演化支,可谓非常成功。但长久以来,关于它们的具体起源、演化、分类依旧存在诸多的疑点和争议。

由于这本身是一个非常庞杂的课题,学疏才浅的我就不在此班门弄斧了,针对这个问题简单的进行拆分并阐述下自己的看法:

●Q1:鸟类是兽脚恐龙中的一支吗?把「纲」置于「总目」之下的划分合理吗?

答案:是的。以及虽然这样的划分有些让人困惑但生物的分类本身就不能单纯的依赖林奈那套过时的且存在很多漏洞的分类模式,因为林奈的分类法并不能客观严谨的表述各大演化支在系统发生学上的关系。

谈到鸟类的演化就不可避免的要先了解恐龙总目这个庞大演化支的成员分类。现存鸟纲不论是在其种群的广泛分布适应性、种群数量、外观差异、生态位分布等多个层面上,都完全具备独立成一个“纲”的基础和条件,但既然恐龙总目是一个天然演化支,自然就不可能将鸟类排除在外。

抛开分类学上冗杂、混乱的分级分类单元不谈,那么将鸟纲整体置于恐龙总目之下之后,又是一个怎样的位置呢?

→具体来说其演化关系为:蜥形纲 – 主龙形下纲 – 主龙形类 – 鸟颈类主龙(鸟跖类)- 恐龙形态类 – 恐龙形类 – 恐龙总目 – 蜥臀目 – 兽脚亚目 – 虚骨龙下目 – 手盗龙形类 – 手盗龙类 – 彭纳盗龙类 – 近鸟类 – 真手盗龙类 – 鸟盗龙类 – 鸟翼类 – 鸟纲(反鸟亚纲+今鸟亚纲)

所以,因为鸟纲的存在,让兽脚亚目成为恐龙总目中唯一有幸存种群存在的演化支。

或许鸟类作为整个鸟颈类主龙中硕果仅存的遗孤是幸运的,但在那场发生于 6600-6500 万年前的白垩纪 – 古近纪大灭绝事件中,整个鸟纲其实也损失惨重。

这其中,反鸟亚纲全军覆灭,无一幸免。仅凭着一小群残存的小型今鸟亚纲保存着微弱的火种熬过了漫长的黑暗,迎来了新生代开局后的第二次全面辐射演化,成为蜥形纲中最优势的种群。

关于这一部分鸟类是如何大难不死躲过浩劫的,这就又是另一个值得探讨的话题了在此就不再多说。

这张图主要是手盗龙形类的演化谱系。鸟纲属于其中一个次演化支。

而这一连串让人头晕眼花如俄罗斯套娃般一环扣一环的分类层级中,最容易让人混淆的就是鸟翼类(Avialae)鸟类(Aves)两者在概念上的差别了。

说到「鸟翼类」,关于它的定义学界一直在不断调整其范围,之前普遍的描述是:在兽脚亚目中,具有羽毛并有一定扑翼能力用于飞行的所有物种及其这个物种的后代。[※该定义由法国生物学家雅克.戈提(Jacques Gauthier)于 2001 年提出]

根据这个定义给出的解释,鸟翼类包括了其后代演化支——鸟纲。需要注意的是鸟翼类>鸟类,但鸟翼类≠鸟类。简而言之就是:鸟类肯定属于鸟翼类,但鸟翼类的成员却并不一定都是鸟类。(大致可以类比“哺乳类和哺乳形类”两者的关系)

目前已知的鸟翼类中,最早的成员是晚侏罗纪时期的始祖鸟,但始祖鸟通常不被划入鸟类之中。(虽然在大众认知和绝大部分教科书中,始祖鸟一直被当做为最早的“鸟类”)

由于鸟纲的定义与鸟翼类存在不少重叠,容易引发冲突,故而Jacques Gauthier提出重新定义关于鸟翼类的表述,修改为:“所有现存鸟类的最近共同祖先与这个祖先的所有后代。”这也意味着按照这样的冠群定义使得某种程度上,今鸟亚纲(Neornithes成为了鸟纲的次异名(因为今鸟亚纲是鸟纲唯一幸存次演化支,两者概念相同)

近鸟龙 Anchiornis,一种小型的原始鸟翼类。
小盗龙是鸟翼类中最著名的成员之一。不过它们并不具备扑翼飞行的能力。
近鸟龙。一种生活于侏罗纪晚的鸟翼类。它们能够在地面快速奔跑,同时也具备一定的滑翔能力。
鸽子骨骼解析图。可以看到大部分拥有飞行能力的今鸟类都具有发达的龙骨突且整体骨架轻盈,相比兽脚类祖先已经高度特化。

而在古生物学界,长期以来对于鸟翼类的传统定义模糊不清,通常习惯的概念范围为:在兽脚类恐龙中接近于鸟类而与驰龙科关系较远的所有物种。根据这个定义的话,属于鸟翼类而不属于鸟类的物种就很稀少了,如:树息龙属。但很自然的,这样一来关于始祖鸟的分类地位就出现了混乱。

所以根据雅克.戈提 修正后的定义:始祖鸟属于鸟翼类而不属于鸟类。而他的这一提议目前已经被古生物学界与鸟类学研究领域广泛采纳。但很多时候,我们为了口头上的表述方便和语境上的习惯使然,依旧偶尔会把整个鸟翼类笼统的称呼为“鸟 / 鸟类”

始祖鸟其实并不是严格意义上的“鸟类”,而是一群同鸟纲有着非常密切关系的原始鸟翼类。
曙光鸟。一种大小接近鸽子的小型鸟翼类恐龙,它们也有些典型的四翼结构。

根据化石显示,大部分的早期鸟翼类都出现在晚侏罗纪时期的牛津阶(距今约 1.6 亿年前),除始祖鸟之外,比较知名的代表性物种有:近鸟龙、晓廷龙、曙光鸟。尽管体型外观各有差异但它们都无一例外的有着一些不同寻常的共有衍征。

这些解剖特点有:后肢脚趾第二趾具有大的爪子,可用于在地面活动;后肢同前肢一样,普遍具有长羽形成所谓的“四翼”结构,可用于在空中滑翔、飞跃。

鸽子(家鸽)骨骼示意图。特化的龙骨突是所有具备飞行能力的突胸总目(今颚类)鸟类共有的特征,上面附着发达的胸大肌,为前肢翅膀扑翼飞行提供强劲动力。
鸸鹋骨骼。平胸总目(古颚类)普遍不具备飞行能力,因此并没有发达的龙骨突结构,但后肢骨骼较为粗壮,擅于奔跑。
鱼鸟的生态位接近现代的海鸥等鸟类,它们的骨骼构造已经非常先进,但龙骨突依旧不够发达。

而这几种特征在后期更进阶的鸟类身上已经逐渐消失,由此可以清晰的看到在鸟类飞行能力不断提升的演化之路上,基干型鸟翼类处于最原始的位置。而得益于鸟类飞行能力的持续强化,它们开始往其他兽脚亚目恐龙无法或者很少涉足的生态空间辐射并取得了成功,如:森林树梢的上层空间、湿地 / 湖泊等浅水地区、以及低空和丛林等。在缓解了来自其他兽脚类恐龙的竞争压力的同时,也进一步拓展了整个恐龙种群的生存空间,并不断蚕食了中小型翼龙目的生态位,迫使翼龙往大型化的特化之路上演进并最终将其逼上绝路。

另外,还有一个比较冷门的概念也可以顺带一说,那就是扇尾亚纲(Ornithurae)。

这个概念是在 1866 年由恩斯特.海克尔(Ernst Haeckel)首次提出并使用,指的是:具有现存鸟纲尾部特征的鸟类(即:具有愈合的尾综骨和少于 6 节的融合脊骨结构),主要用以区分具有坚尾龙类普遍僵硬、修长的尾椎骨结构的始祖鸟。

黄昏鸟目堪称是白垩纪的“企鹅”,成为中生代最成功的水陆两栖鸟类种群。
扇尾鸟。属于扇尾亚纲的基干群之一。
黄昏鸟是中生代的优势半水生鸟类,生态位趋同于现代的企鹅。
卡冈杜亚鸟体型非常趋同于现代的平胸总目,但两者并无关系。它们是一种早期的陆栖今鸟亚纲。
外观接近鸡形目的巴塔哥尼亚鸟属于今鸟亚纲,它们是中生代非常成功的地栖鸟类之一。

而这个概念也基本与今鸟亚纲相重合成为其次异名,因而目前基本被今鸟亚纲所取代。目前仅用于表述一部分具有原始衍征的最基群鸟类如:黄昏鸟目、神翼鸟、鱼鸟、义县鸟、燕鸟等。

为了更加严谨的表述,我们一般习惯于将除开鸟类后的恐龙(即:兽脚亚目、蜥脚亚目、鸟臀目)称呼为“非鸟类恐龙”。不过这并不是一个有效的分类单元仅仅只是一种通俗称谓,因为它剔除了鸟纲这个兽脚亚目后代,因此无法构成一个天然演化支。

同样的,鸟翼类 / 鸟类也可以表述为“鸟形恐龙”,它们都是恐龙总目这个演化支的次演化支。如果实在觉得“恐龙总目”之下突然出现一个“鸟纲”显得突兀的话,那其实可以换一种思路去理解,即:恐龙总目由“非鸟类恐龙”(蜥臀目 – 兽脚亚目 / 蜥脚亚目;鸟臀目)和“鸟形恐龙”(鸟纲)共同组成。

当然,这也只能作为一种非正式的语言表述而无法作为正式的分类单元。但相对来说,这样划分之后,就更加便于理解两者之间的关系了。随着研究的不断深入和越来越多的化石证据的出现,我们愈发感觉到“龙”与“鸟”之间的界限越来越模糊,毕竟它们本来就是“一家人”。

今鸟亚纲的突胸总目(今颚类)为了适应飞行需要,身体结构都做出了很多改变。骨骼数量减少并愈合、中空结构充满空气和毛细血管、气囊呼吸系统以及复杂的覆盖全身的羽毛。

那么我们不妨再试着大开一下脑洞想象一下:如果哺乳纲经历了一场大灭绝之后仅存啮齿目存活下来,然后这一小支啮齿目在腾出来的生态位真空中迅速爆发式的辐射演化并适应性的进化出多个形态各异的种群,我们也完全可以把这些数量众多、门类繁多的啮齿类独立出哺乳纲成立一个全新的“啮齿纲”,并把已灭绝的哺乳类称呼为“非啮齿类哺乳动物”,那这两者间的演化关系也会出现“纲”下面套着另外一个“纲”的尴尬局面。

生物的演化史上像鸟类这样,从一个萎缩后的大演化支下的残存次演化支再次壮大的例子还有很多,比如哺乳纲。它也是从合弓纲 – 兽孔目 – 犬齿兽亚目 – 真犬齿兽下目中的哺乳形态类残存的一支演化而来,并在新生代再次壮大,因此也同样产生了“合弓纲是否包括哺乳纲”的争论。

纵观今天地球上种类繁多的所有鸟类种群:从奔跑的鸵鸟到潜水的企鹅、从优雅的火烈鸟到凶悍的白头海雕、从吮吸花蜜的蜂鸟到偏好腐肉的秃鹫、从被人类大规模圈养的鸡鸭到高贵华丽的孔雀,它们都无一例外的属于今鸟亚纲这个演化支——这个鸟纲也是兽脚亚目恐龙唯一幸存至今的幸运儿。

鹤鸵
蓝孔雀
长尾山雀
琉璃金刚鹦鹉
红冠蕉鹃

●Q2:翼龙与鸟类存在演化上的关系吗?

答:没有。

翼龙目(Pterosauria)作为鸟颈类主龙中的重要一员,很早就同恐龙形态类分家并各自独立演化,翼龙目恐龙总目还有兔蜥科共同构建成鸟颈类主龙(目前已经重新分类为鸟拓类)这个演化群。

鸟类、大部分恐龙、翼龙都有着类似的气囊呼吸系统,这是它们从共有的主龙类祖先继承的祖征。

所以尽管翼龙尤其是后期进阶型的翼手龙亚目出现了许多与鸟类相似的衍征,比如:气囊呼吸系统、无牙角质喙、中空的骨骼、退化的尾椎骨等,但这也只是趋同演化所致,这其中很多衍征其实是鸟类和翼龙从它们的鸟颈类主龙祖先身上继承的共有衍征 / 祖征而已。

前面提到,恐龙总目(含鸟纲)属于恐龙形类 – 恐龙形态类,这个演化支还包括了西里龙、马拉鳄龙等与恐龙的祖先关系十分密切的小型鸟颈类物种;而另一支则是翼龙形类,它包括了翼龙目、斯克列罗龙等演化支。

马拉鳄龙属于恐龙形态类,但并不属于恐龙总目。这是一群与恐龙关系最为紧密的演化支。
三叠纪时期陆地的统治者是以波斯特鳄为代表的镶嵌踝类主龙,它们捕食兔蜥、早期的小型恐龙。

※【Tips】鸟颈类主龙(鸟拓类)的鸟颈形类(Avemetatarsalia)其下包括两个次演化支:

>>1.恐龙形类:恐龙总目(Dinosauromorpha)

马拉鳄龙(Marasuchus)、西里龙(Silesauridae)等与恐龙亲缘关系很近但不属于恐龙总目的演化支。

>>2.翼龙形类:翼龙目斯克列罗龙

由于翼龙目和恐龙总目中的蜥臀目 –†兽脚亚目非鸟类恐龙、†蜥脚亚目、†鸟臀目、鸟纲 –†反鸟亚纲都已在白垩纪晚期全部灭绝,现存的鸟纲 – 今鸟亚纲成为唯一存活的鸟颈类主龙代表和唯一幸存的兽脚亚目演化支。

所以,虽然翼龙目并不是恐龙,但它们也确实是所有蜥形纲种群中,同恐龙总目关系最近的一个分支,算得上是恐龙名副其实的近亲。(至少相比属于假鳄类[即:原来的“镶嵌踝类主龙”]的鳄形超目成员远亲,同属于鸟拓类的翼龙跟恐龙有着更紧密的血缘。)

有关翼龙目具体的分化、演进在这里就不再展开,有兴趣可以猛戳下面的文章链接,我在之前的“史前公园”系列里有详尽的叙述。

阿尔萨斯肉丸:「Prehistoric Park 丨史前公园◎6」天空帝国,谁主沉浮?—翼龙王朝简史

明白了这一点,“翼龙就是会飞的恐龙”这样荒谬的说法自然就戳破了。

有趣的是,翼龙目崛起的时间同恐龙总目大致相同(三叠纪晚期),并最终伴随着所有非鸟类恐龙在白垩纪末期销声匿迹。它们作为第一批飞上蓝天的脊椎动物,占领了之前从未有其他羊膜类涉足的全新生态位,开启了脊椎动物的天空帝国 1.0 版本。

大型翼龙与大型会飞的鸟类翼展比较。相比之下,皮膜结构的翅膀天生更加适合大型化,翼龙得益轻松突破鸟类在飞行能力与体型之间的瓶颈。
鱼鸟同翼龙抢食捕获的鱼类。白垩纪时期,两者展开了激烈的交锋。
具备飞行能力的鸟类中体型极限代表——桑氏伪齿鸟
风神翼龙是大型化翼龙种群中的代表,它们的体型犹如一架小型飞机。

然而一片欣欣向荣之下早已暗流涌动,一支在侏罗纪晚期不起眼的小型兽脚亚目恐龙正悄然崛起并伺机发起了挑战。最终在白垩纪,第一次辐射演化的鸟纲两大阵营(今鸟类与反鸟类)一步步把翼龙种群的生存空间蚕食、挤压,在中小型生态位上取得了压倒性的优势。而由于生理机能上的差异,翼龙先天在大型化上有着鸟类无可比拟的优势。

当然了,演化是把双刃剑。翼龙在后期大型化的道路上一骑绝尘高度特化最终夺得优势生态位的同时也间接锁死了后路,最终全盘覆灭。

披着羽毛的会飞的恐龙—鸟类,不声不响中打败了它们的前辈—翼龙,取得了天空的统治权,并成功在新生代翻盘,开创了天空帝国 2.0 版本。

那么,鸟类究竟是靠着哪些优势在同翼龙争夺蓝天霸权的拉锯战中胜出的呢?翼龙的覆灭是偶然还是必然?

无齿翼龙的雌性体型对比。它们是白垩纪北美洲非常常见的翼龙种群。
翼龙的翼膜结构其实远比我们想象中的复杂,皮膜中充盈了许多细微的毛细血管并覆盖着部分绒毛。

相比翼龙由延长的指骨附着皮膜而形成的皮翼不同,鸟类的翅膀则是由更加复杂的羽毛附着在肌肉上形成的双翼。这其中,每一根羽毛都是由两侧平行伸展出的羽枝组成,羽毛顶端的羽小枝呈钩状结构,称之为“带钩羽小枝”,而羽枝的另一侧则具有边缘卷曲的片状结构,称之为“滑道羽小枝”,这样“钩 + 滑槽”的结构使得羽毛即使掉落也能再次补充生长,具有非常强的自我修复能力和延展性。

现代鸟类的羽毛结构。看起来轻盈的羽毛其实构造十分精妙,不仅能够适应飞行时遇到的复杂空气流体力学因素,还能防水和保暖。

反观翼龙,其翼膜一旦撕裂破损则几乎不可逆。也因此,鸟类能够深入更加密集复杂的丛林深处和错从复杂的低矮空域,抢占更多生存空间获取更多的资源。

三种具备飞行能力的脊椎动物(翼龙目 / 鸟纲 / 哺乳纲 – 翼手目 )翅膀结构对比。相比之下翼龙的翼膜结构最适合大型化。

不过翼龙的翼膜结构也有着一个鸟类望其项背的优势,那就是非常适合大型化。

受制于高代谢率机能的因素,同等重量下鸟类需要获取比翼龙更多的能量,而它们所处的环境资源是有限的,并不能满足如此大的食物供给。因而鸟纲在大型化道路上阻力重重,体型如果进一步增大伴随而来的就是飞行能力的丧失,最终只能重回地面。而与此同时,同属于鸟颈类主龙的翼龙则轻松突破了体型与飞行能力之间的瓶颈,在大型化的道路上扶摇直上,远远的甩开了同等体型位面上的鸟类,可谓是最成功的飞行脊椎动物。

然而有得必有失。

翼龙与鸟类在运动机能尤其是后肢的结构差异上决定了它们最终的命运。

整个翼龙目其下大小不一的所有科,后肢的运动能力都十分有限。当它们在陆地行动时更加接近于四足动物而非恐龙、鸟类这样的二足步态。再加上由于皮膜连接着前肢与后肢之间的肌肉,使其无法依靠后肢单独站立行走或奔跑,这就造成翼龙无法像鸟类一样做到兼顾陆地 / 天空两种生态位,更别说重回陆地与其他竞争者分一杯羹。

大型翼龙在陆地运动模式的模型复原图。它们采取四足步态,以接近于哺乳纲熊科脚掌触地的方式移动。

相较之下,鸟类的翅膀是由前肢独立演变而来,不论体型大小都无需借助后肢辅助即可自主运动。因而即使一部分鸟类在生存竞争中放弃了飞行能力也能重返陆地生存,或下海捕鱼或大地上疾驰都毫无阻碍,这是翼龙无法做到的。

大型翼龙起飞之前,需要弹射才能升空。
南翼龙的后肢相对来说更加修长但依旧无法做到鸟类后肢在地面的灵敏度
Dimorphodon 双型齿翼龙。一种早期的小型翼龙,属于喙嘴龙亚目。它们在陆地行动时需要借助前肢,采取四足步态。
以小盗龙为代表的鸟翼类,具有独特的四翼结构。不过它们并没有扑翼飞行能力,只能在树枝间滑翔。这也算是早期鸟翼类对飞行模式的探索之一。
中国鸟龙属 sinornithosaurus。这是一种小型的树栖兽脚亚目恐龙,它们也没有飞行能力。同小盗龙一样,具备初级滑翔能力。鸟翼类和鸟类自始至终,前肢与后肢的功能分工都很明确。
大部分翼龙在陆地休息、进食时,都需要借助前肢支撑身体。尤其是一些大型翼龙。
鹤鸵骨架。相比之下,由于后肢具备独立的运动机能,部分鸟纲退化掉飞行能力后还能够重返陆地生存。
几维鸟。新西兰的著名国鸟,它们的前肢翅膀几乎萎缩不见,但却具有非凡的奔跑能力和敏锐的夜视、嗅觉,在新西兰这样的孤岛生态位上,取代了啮齿目的地位。
巨嘴鸟。翼龙和鸟纲都各自独立平行演化出无牙角质喙,这一衍征对高度依赖飞行的物种来说具备普遍适应性,因此出现在两个没有演化关系的物种上也就不足为奇了。

纵观翼龙目的演化历程可以发现:它们是一群高度依赖飞行能力的特化种群,比鸟类有着更加单一且特化的衍征,为飞行而做出的适应性改变也更加激进是一种更加纯粹、专性的飞行生物。

鸟类由于身体结构的原因,使得它们能够牺牲飞行能力的同时依旧保留在陆地的运动能力,且前肢翅膀相对翼龙的翼膜结构更有可塑性,能够根据生存环境的不同做出顺应的适应性演变,如:企鹅目的前肢就趋同演化为鳍状能够在水下快速游动、骇鸟科翅膀上没有完全愈合的指骨特化成肉钩用于捕猎时进行抓握固定。

种种多样化的适应性改变都使得鸟类相比翼龙具备了更加灵活的生存策略,从而得以占领更多的生态位,避免种群在突发的大灭绝事件中全军覆没,提高了生存几率。

因此鸟类同翼龙相比,它们反而没有那么完全依赖飞行能力和天空这个单一生存环境。而在非鸟类恐龙灭绝之后的新生代,空缺出来的陆地生态位真空反而还促使部分鸟类抢占先机顺势崛起,在哺乳纲全面接管统治权之前一度分庭抗礼,填补了之前兽脚亚目同门的位置。即使后来这些凶悍的大型陆行鸟都退出了舞台,然而时至今日,依旧有不少地栖鸟类占据着不少陆地生态位并非常成功。

形形色色的各种鸟类喙部。尽管没有牙齿,但是角质喙能够根据不同种群鸟类的生态位,适应性的演化为不同形态满足进食的需要。
大部分后期的翼手龙亚目种群也平行演化出各色形态各异的无牙角质喙。不过翼龙与鸟类的喙并不是同源器官,而是趋同演化所致。

而这一切,对翼龙来说都是无法做到的。即便它们熬得过大灭绝,面对更加多样化的鸟纲种群和异军突起的哺乳纲翼手目(蝙蝠)的挑战,未必就能胜出。〔这样的例子在新生代早已有之,比如有幸逃过一劫的离龙目因为生态位同鳄目的重叠导致竞争失败最终在中新世灭绝。〕

而翼龙这样更加“纯粹” 地为了飞行而高度特化的动物,正好缺少了像鸟类一样「备用钥匙」,可以说是非常遗憾了。

某种程度上,翼龙守住了在天空这一块生态位的顶级霸主地位,然而不经意间也丢掉了保底的中小型生态位,为大灾变来临后的覆灭埋下了一枚定时炸弹。

[* 尽管在白垩纪晚期依旧还有部分中小型翼龙种群的存在,但在生态位分布上与同期的鸟类相比已经不占优势,大型的、依靠滑翔的翼手龙亚目才是当时的主力军。]
在海平面低空飞行捕食乌贼和鱼类的掠海翼龙。它们的生态位在新生代被信天翁等大型鸟类取代。

大灭绝事件对翼龙种群而言,也许是个小概率的偶然事件,然而从它们的种群演化路线上看,翼龙目的整体衰败直至消亡也是一个无法避免的结局。但不论怎样,作为鸟类的前辈、恐龙的近亲、首批飞天的脊椎动物,翼龙目都足够名垂青史。

[THE END]

Posted in: 生活

有没有以前很火,现在却被发现是很危险的发明?

头图

居里夫妇自从 1898 年发现了钋和镭,4 年间发表了 32 篇论文,其中就包括在辐射下,癌细胞比健康细胞死亡更快的事实——这蕴含着不可估量的医学应用前景,他们很快尝试在某些浅表的肿瘤上固定含镭的放射源,肿瘤果然迅速缩小了,在那些幸运的病人身上,正常细胞趁机取代了癌细胞,恢复了患者的健康。

于是就像今天的人们对种种“抗癌功能”的事物趋之若鹜,当时的保健品行业立刻抓住了其中的商机。法国药剂师亚历山大·雅各宾(Alexandre Jaboin)提出了一种“微居里疗法,1 克镭 226 的放射性活度被称为 1 居里(公式:1 居里(Ci)=3.7×1010 贝克(Bq)),这种疗法就是让人喝下含有几微克镭元素的水,号称微量的辐射能给健康的细胞增加能量,延年益寿。

结果各种含镭的牙膏、面包、雪茄、药片、巧克力、化妆品……都成功地在 20 世纪初掀起了消费热潮,这些核辐射刺激骨髓制造了更多红细胞,因此在短时间内的确营造出了有益健康的错觉。

与此平行的,镭盐自从问世就以暗中发光著称,这是因为α射线有很强的电离能力,美国的镭发光材料有限公司(Radium Luminous Material Corporation)在 1917 年研发了镭与硫化锌的混合涂料“Undark”,释放的光格外明亮,给夜间行军的载具涂装仪表盘再合适不过了。

同年美国加入一战,这家公司也大发了一笔战争财。随着夜光手表在战后大流行,这家美国镭企业在新泽西等地开了许多工厂,雇佣了许多年轻女工用给表盘刻度刷涂料,笔尖劈了叉,就叫她们用嘴抿一抿。有些无知的年轻女工觉得好玩,还把这涂料抹在嘴唇和指甲上,晚上下班后在酒吧里大放异彩,殊不知已经大祸临头。

1922 年,22 岁的女工茉莉·马基亚(Mollie Maggia)形容骇人地惨死了:牙齿迅速脱落,下颌骨像朽木一样千疮百孔,充满了大型的坏疽。

当时死亡证明说这三期梅毒,但我们现在知道这是“镭毒颌炎”——因为镭元素虽然没有任何生理功能,但它很容易被机体误认作同族的钙元素用来构建骨骼——尤其是更新最快的下颌骨,然后在那里用放射性缓慢地杀死组织。

除了镭毒颌炎,浑身乏力、重度贫血、牙龈溃烂、关节癌症,迅速在镭企业的女工身上爆发出来,一个个正当妙龄就形销骨立,许多人不得不切掉整个下巴,连残喘都带着放射性:终于在 1925 年,5 名女工决定联名起诉,并在两年后争取到了支持自己的律师。

这场诉讼轰动了整个西方世界,出现在各大报刊的醒目位置上,镭企业一度试图拖延审判耗死当事人死无对证,但精明的法医在宣判前给最早死亡的镭姑娘开棺验尸,她们的骨灰果然带有强烈的放射性,能搁着黑纸给照片底片感光。铁证如山不得抵赖,镭姑娘们在弥留之际向世人揭示了核放射性的阴毒力量。

在劳工权益组织的声讨呼吁下,不但镭企业支付了高额的赔偿和抚恤,在判例法系的美国,各行各业的工人从此都能以镭姑娘为先例,为自己的职业病向雇主提起赔偿,接推动了职业安全标准等规范的建立,镭姑娘的申诉已经成为铭刻于历史的悲壮事迹。

镭的毒性不分阶级,埃本·拜尔斯(Eben Byers)是个著名的运动员和实业家,他在药商煽惑之下喝了几千瓶镭补(Radithor),失去了整个下巴,1932 年惨死之后,骸骨甚至能在照片底片上洗出轮廓。这类事故在 30 年代的爆发同样引起了媒体的广泛关注,并最终推动了食品药品管理局(FDA)对含镭保健品的禁绝。

在这些血泪的教训下,镭的闹剧终于在 1935 年左右退出了历史的舞台。

本回答所有截图和内容摘引自《发光的骨头 | 混乱博物馆》后半部分。

发光的骨头 https://www.zhihu.com/video/1102596690787364864

想了解更多你不知道的知识,请在微博、微信公众号、哔哩哔哩、YouTube,搜索「混乱博物馆」,关注我们。

Back to Top