Skip to content
  • 51蛙吖蛙元宇宙电脑版入口
  • 51蛙吖蛙官网
51蛙吖蛙 – 3D社交空间

51蛙吖蛙 – 3D社交空间

投稿、社交、聊天就来51蛙吖蛙元宇宙

  • 首页
  • Toggle search form

分类: 生活

WPeMatico Campaign中添加的类别

为什么只有中国饮食没有像日本韩国那样被西化?

头图

讲点根子上的真东西。

东亚食物西化最核心的部分是主粮的西化,也就是米饭被面包代替。只有面包更高比例的作为主食,才能谈整体食物被西化。

首先我们从中国烘焙行业最大的头疼问题讲起:

我有次和我国头部烘焙企业交流,他们最头疼的,就是在中国面包一直都是冲动性消费和奖励性消费,面包的主食化率就是死活上不去。

这个「面包主食化率」很关键。

面包主食化率低,反映到烘焙店微观上:面包的外卖单量就是上不去,面包产品越来越甜品化零食化,面包店大量贩卖蛋挞、生日蛋糕、月饼桃酥蛋卷这类「不是为了吃饱」产品去做营业额的主力。

反映到行业宏观上,非刚需的消费动机,导致整个烘焙店的复购不行,所以市场集中度也不行,难以诞生日本山崎敷岛、韩国巴黎贝甜多乐之日这样高集中度的面包品牌。

目前比较火热的中式烘焙店走的是一种类似综合甜点店的路子,也完全不是主食路子。

看过数据,日本的面包主食化率可以接近到 20%,日本家庭买面包的家庭支出甚至超过了买大米。日本和韩国为什么能够这样?

(日本官方统计 by 日经数据)

两大原因,缺一不可。

第一因为「美援面粉」,美国二战后 50 年代,美援给日本韩国的都是面粉,核心就是拿来做面包。

民众容易获得便宜面粉,是这件事情的先决条件。

日式猪骨拉面、韩国炸酱面、日清方便面、韩国三养方便面都是这个阶段,就着这个东风做起来的。

第二,「学校食堂」,昭和时代日本,625 战争后韩国学校食堂,都开始大规模供应「面包」作为学校伙食。美援面粉也是优先给学校食堂的做面包。

儿童时代吃的东西会一直影响人的一生。日本韩国人从小就不觉得拿「面包」作为一顿饭有什么问题。

美国这样子当然也是为了打开东方的大门,为了卖他们的面粉。

我们从快消的角度去分析,如果要扩大一些产品的用量,无非是两个办法。

①扩大产品现有应用的消耗。美国面粉价格曲线一拉到底,造成的结果,是成年人在把面粉全都拿来做面条。

②扩展产品的使用场景。也就是把面粉拿来做面包。但是成年人的饮食习惯改不了,必须从娃娃抓起。

问题来了。中华民族特殊吗?在这种食物西化攻势下能够抵御吗?

我的答案是,现在可能可以抵挡,在当时的环境下很难抵御。

我国台湾在同时代也收到了大量的面粉,同样面包进到当时台湾小孩「营养午餐」去了。

面粉价格一拉到底,中式面食应用用量增加,眷村老兵用面粉做了台湾牛肉面。

再看美国佬开发的新使用场景。

除了在中小学「营养午餐」中提供面包。

台湾 1967 年成立了「美国小麦协会」还有「台湾区麦面食品推广委员会」(现在是中华谷物研所),这个组织培养了大量的烘焙从业人员,据说有十万从业左右。

培训烘焙什么的呢?其实就是教着烤面包,开面包店。有了面包店,面粉就有更多的使用场景。

(评论区有台湾朋友讲了当时的一系列的措施,我置顶了)

在这一系列的组合拳下去,我们台湾人民吃面包的比例眼见着日渐高了上去。。。

图源中泰证券
中国台湾麦米消费占比 by 东北证券

到了 2015 年,台湾吃小麦的比例已经到了吃大米比例的 80%。(这个数据也包含吃饼吃面条吃包,没找到纯吃面包的数据,哪位高人有可以帮我补一下)

这个比例的厉害之处就在于,台湾是热带地区,小麦是温带植物,面粉 99%全靠进口。。。

所以啊。。。。我们现在的食物不够西化,主要还是要怪这帮西方人不给我们送面粉!!!

查看知乎讨论
浏览量: 25

光速为什么定义为 299792458m/s,而不是取整数 300000000m/s?

头图

这只能怪,法国大革命进行得太早,而激光器发明得太晚。

人类是偏好整数的动物。股票指数也好,身高也好,人类对整数有着非理性的偏爱。

那为什么光速不是个整数呢?非得搞个 299792458 米 / 秒,算也不好算。

其实,人类的本性并没有变,这正是因为人类喜欢取整造成的。

第一次凑整:单摆

光速的单位,是米 / 秒。秒这个单位我们比较好理解,在 1960 年之前,秒就被定义为平均太阳日的 86400 分之一,一看就是个挺整的数,关于“秒”的历史,我们以后再说。我们先说说这个“米”,它决定了光速是不是个漂亮整数。

在法国大革命之前,法国的长度单位并不统一,最常见的一个单位是 pied,全称为“pied du roi”,意为”国王的脚“,对应的英文是 foot/Paris foot/French foot。1 pied = 32.48 厘米。比它大的单位是 toise(念作脱袜子),在最开始,6 pied 就是 1 toise。toise 这个单位是查理大帝在 790 年引入法国的,意为两臂张开时左右手中指尖间的距离[1]。

我们知道,1793 年,法国大革命的革命者以“叛国罪”把国王路易十六送上断头台给咔嚓了。那么计量单位自然也要与国王划清界限,最好是一个与人无关的自然值,最好这个新的度量衡体系能被所有国家采用。也就是说,新的度量衡体系必须是普适的,而且在未来也能保持有效。

国民制宪议会就把这个任务交给了法国科学院。那用什么作为标准呢?

法国科学院一开始打算用单摆。单摆,是荷兰科学家惠更斯在伽利略的基础上于 1656 年发明的。

初中物理老师告诉我们,单摆在小幅度振荡时,周期只取决于其长度,即单摆的周期 T 为:

虽然这个公式是我们基于现在的单位制写出来的,但不妨碍我们去理解周期与摆长的关系。我们给正好在 1 秒的时间内从左摆到右的单摆起一个专用名字:秒摆[2](我们现在知道,秒摆的摆长很接近 1 米)。1660 年,英国皇家学会已经提出把它作为标准长度单位的提案了。1675 年,意大利科学家 Burattini 将这个长度命名为“metro cattolico”,意为“通用单位”,这个词也是法语“米(mètre)”的由来[3]。

1 秒是个多么美的整数值,所以 1 米就从这个整数出发给定义好了。

但是,法国天文学家让·里歇尔在南美洲(现法属圭亚那)发现,秒摆的长度会随着纬度的变化而变化(背后是公式中的 g 有变化),法属圭亚那的秒摆与巴黎的秒摆摆长相差了 0.3%。所以不得已,只能硬性规定要以法国所在的北纬 45 度的秒摆摆长来定义 1 米的长度。

第二次凑整:子午线

虽然上面涉及的数值都是漂亮的整数(5 也算是广义凑整的一员),但这和前面的“普适”就有了冲突,凭什么要用北纬 45 度,而不用其它国家所在的纬度?

因此,以拉格朗日和拉普拉斯等人为代表的法国科学院成员决定寻找更“普适”的定义。在当时,欧洲天文学家最流行的研究之一,就是测量地球,事实上,早在 1735 年(也就是雍正驾崩那年),法国科学院就派出科学家 Pierre Bouguer 等人开始测量赤道和极地附近 1 度子午线对应的弧长。Bouguer 在秘鲁一测就是十年[4],最终测得在赤道附近海平面上的 1 度对应 56749 toise[5](当时已经知道地球不是完美的球体而是椭球形)。1766 年,路易十六的爷爷路易十五就指示科学院将他测得的 1 度弧长的 56749 分之一作为 1 toise(Toise du Pérou)。这是量出来的值,就算想取个更整的数也没办法。

现在,既然要搞一个新单位,那就可以取整了嘛!我们只要人为把新单位“米”定义为地球的某个尺寸的整数分之一就好了嘛。于是在 1799 年,法国科学院把米定义为:穿过巴黎的那根经线上从极点到赤道的距离的 10,000,000 分之一。

非常的凑整。整得不能再整了。

第三次凑整:光速

上面说了这么久的“米”,终于要说“光速”了。比较精确的光速值(精度在 5%以内),是 1849 年由法国物理学家菲索测得的。也就是说,人类测得较准确的光速时,它的单位(米 / 秒)已经被定义好了。当时,菲索算出的值是 313,274,304 米 / 秒。他在 1864 年提出,可以用这个值来作为长度度量标准。

斐索 – 傅科仪示意图:在已知距离(8 千米)外放下一面镜子,再测量光到达镜子反射回来的时间

但问题是,这个用机械齿轮算得的值过大了。1907 年,科学家 Rosa 等人利用麦克斯韦方程的光速表达式

,通过测量这里面的真空介电常量和真空磁导率,间接测得光速为 299,710,000±30,000 米 / 秒。1950 年,史密斯等人用谐振腔法测得 299,792,500±3,000 米 / 秒。1958 年用无线电干涉测得 299,792,500±100 米 / 秒。

这个精度已经是当时技术下的最好精度了。但由于还是有每秒正负 100 米的误差,所以没办法凑整。也就是说,我们这个时候没法把光速定义成米的某个整数值,因为它的精度还不够。

就在这个时候,激光诞生了。1960 年 5 月 15 日,梅曼等人成功制成了世界上第一台可操作的激光器。1972 年,Evenson 等人利用 3.39 μm 甲烷吸收稳定的氦 – 氖激光干涉的方法,测得光速为 299,792,456.2±1.1 米 / 秒和一个 peak 值 299,792,458.7±1.1 米 / 秒。1973 年,Baird 等人用二氧化碳激光器测得光速为 299,792,457.2±6 米 / 秒,米定义咨询委员会(CCDM)[6]认定光速为 299,792,458.2±1.2 米 / 秒[7][8]。

1958 年之后的光速测量结果

注意看,虽然测量值都不尽相同,但这时每秒光速值的精确度已经逼近到米了。于是,在综合了之前所有测量结果后,在 1975 年第 15 届国际计量大会(CGPM)上,光速被人为建议用 299,792,458 米 / 秒这个值。(人类的取整欲!)

不同机构和仪器测得的光速值,中间虚线为 CCDM 的值

从此刻开始,即使测量光速的技术继续进步,也不怎么会再影响国际单位制下的光速值的整数部分了。

1983 年,第 17 届国际计量大会正式将米重新定义为“在 1/299,792,458 秒的时间间隔内,光在真空中行驶的路径长度”。

需要注意的是,这里实际上不是用米和秒来定义“光速”,而是反过来,用光速和秒来重新定义“米”这个单位。

为什么不是每秒 300,000,000 米

现在来回答题主的问题。既然这个“米”依然是人为定义的,那为什么不把光在 1/300,000,000 秒内走过的路程定义成 1 米呢?

算一下,这只差了约 0.0692%,也就是万分之七。

问题是,就算是新的米比原来的米短万分之七,也会给已有的精密设备造成难以接受的兼容问题。修订度量标准的主要原则之一,就是任何更改都要对以前的设备和计算造成尽可能小的干扰。

在 20 世纪 60 年代,核能、大规模集成电路和航天等尖端科技中,超精密加工已经开始发展了,到了出定义的 80 年代初,精加工已经达到了 10 纳米级,表面粗糙度已经到了纳米级,加工最小件的尺寸也到了微米级。这时候如果再将米改小万分之七,这些零件都要重新做了。

所以,仅是为了人类的“凑整欲”,就让精加工的工业产品上出现大地震,是完全无法接受的,会受到很大的抵制。(度量衡和单位标准的抵制,历史上不是什么新鲜事)。

如果你觉得这个值太难记,大概率说明你用不上这么高的精度,直接记成 30 万公里每秒,也不影响你做题。

实际上,在做高能物理和场论的题时,我们常会用无量纲单位制,这时真空光速

不仅如此,普朗克常数、万有引力常数和玻尔兹曼常数这几个难记的量,都为 1。这个单位制也称为普朗克单位制。

记住,取整只是人类大脑低效 + 偷懒的产物,并不是这个世界的运作规律。

都读到这儿,点左下角的头像,关注一下我呗~

查看知乎讨论
浏览量: 24

什么节气后蚊子才会消失?

头图

哈哈哈哈哈哈 这是一个非常不错的问题

前天晚上,合肥的友人为了躲避地震从 23 楼沿楼梯狂奔而下。待了半小时后,被蚊子咬的受不了,然后就回家去了。。。这种蚊子猛于地震的态度让我惊诧。

身为北方人,在酷热夏日之际,我通常会期盼着“立秋”节气的到来,期待着一场秋雨一场寒,过几天凉爽的日子。也盼望着蚊虫随之消失。

我生活在山东南部沿海城市,“立秋”之后天气倒是清爽了许多,但是蚊子却没见少,反而增多了。除了常见的库蚊,还增加了伊蚊,被咬的十分难受。

蚊子不会消失 只是隐匿

吸人血的蚊子可能是这个世界上最令人讨厌的生物,不过我们几乎每年都能看到它们。

年年岁岁人不同,年年岁岁蚊相似。每年总有那么几段时间,会被蚊子搞到不厌其烦。

即便温度下降,蚊子也只会藏在隐蔽的角落越冬。待到时机成熟,再次与我们相见。

其中按蚊、库蚊以成虫的方式越冬,当温度过低的时候,蚊子就会躲在安静、潮湿、隐蔽的场所,例如管道、空置房、楼道、地下室、车库和牲畜棚等地方。库蚊和按蚊在此期间一动不动,进入静止期或滞育期,等待温度回升,就会再次出现在人们面前。

伊蚊以卵的方式越冬,会在气温下降时在有水的容器内产卵,等到来年再孵化。

白纹伊蚊与温度的关系

白纹伊蚊 来源:Wikipedia

白纹伊蚊大概是蚊子里最令人害怕的了,它们在白天都非常活跃,不避人且毒性大。更可怕的是还能传播登革热,几乎每年都会有这样的新闻。

白纹伊蚊最显著的外在特征是黑白色的身体和带白环的附肢,因此也被称作“黑蚊子”和“花蚊子”。

作为原产热带的蚊子,白纹伊蚊对高温的耐受力较强,对低温耐受也不算很弱。

研究[1]发现,白纹伊蚊成蚊在 11 ℃时不吸血、不产卵,36 ℃时几乎不吸血,也不产卵,16~31 ℃下均吸血、产卵。而且在不同温度下,白纹伊蚊的成虫存活天数也有较大的差别。

来源:附注 1

可见蚊子也是不喜欢高温的,即便来源于热带,当温度为 36℃的时候,白纹伊蚊的寿命都会大大缩短,平均寿命不到 10 天的样子。

当温度低于 11℃时,白纹伊蚊不再吸血,也不能完成发育和繁殖。此时可视为本年度白纹伊蚊“消失”的节点,此时白纹伊蚊不再吸血,也不会繁育出新的个体。

在此之前的高温日子里,白纹伊蚊已经产下了越冬的卵。等温度持续在 11℃或以下,半个月之后我们就很难再见到活的白纹伊蚊了。

温度对常见蚊虫繁育的影响

除了白纹伊蚊,我国最常见的就是淡色库蚊(北方地区,南方地区常见致倦库蚊,二者生态习性类似)和中华按蚊。

几种常见的蚊子 来源: CDC&Wikipedia

蚊子属于变态发育,会经历卵 – 孑孓 – 蛹 – 成虫四个阶段。任何一个阶段受阻都会导致繁育停止。

蚊子的生命周期(life cycele)改自 CDC

研究人员对国内三种最常见的蚊子进行了实验[2],在 10-40℃温度区间,每 5℃为一个梯度的实验设计,观察三种蚊子的繁殖和发育状况。得出的结果如下图所示。

来源:附注 2
来源:附注 2

三种蚊虫里白纹伊蚊和中华按蚊对温度的适应范围最窄,在 10、15 和 40℃时都不能完成全代发育。事实上其它研究表明[3],中华按蚊能完成全代发育的下限在 16-19℃之间。所以当温度在 16℃以下时,可以视为中华按蚊的“消失”节点,此时中华按蚊不再产卵,不会有新的成体出现。残存的成体吸血率也会下降,温度持续走低后会找到阴暗的地方,以成体形式越冬,以便来年复出。

淡色库蚊非常耐寒,但是不耐高温。只有在 40℃时不能完成全代发育,但在 10℃时依然可以完成全代发育。而且孵化率高达 50%。当温度来到 7-8℃时,淡色库蚊在受到强刺激时仍能完成短距离飞行[4]。所以我们可以将 8℃视为库蚊”消失“的节点。

结语

综上所述,我们可以发现蚊子最适温度在 25-30℃之间,此时蚊子最为活跃。当温度高于 35℃时,蚊子生命活动也会减弱。因此我们每年都会在春末秋头遭遇两次蚊子高峰,夏季温度过高时,蚊子反而会减少。

我国常见蚊子中以淡色库蚊最耐寒,以成虫方式越冬,当温度低于 8℃时生命活动才会减弱,寻觅越冬场所。

中华按蚊也以成虫方式越冬,在 16℃时就会停止产卵。就不再有新的个体出现,现有个体也会寻觅越冬场所。

白纹伊蚊以卵的方式越冬,在 16℃的时候就不再产卵,但直到温度下降到 11℃之前仍会吸血。

所以蚊子什么时候消失,看一下当地的天气预报就好了。

查看知乎讨论
浏览量: 28

为什么人被烫伤会起水泡,而煮肉烤肉的表面却很光滑?

头图

烧伤水疱是一种生活反应。

为什么题目问的是“烫伤”,而这里是“烧伤”?

广义的烧伤,又被称之为热损伤,包括了炽热的液体、固体、火焰和高温的气体引起的损伤。

所以。。。医院里一般也都是“烧伤科”。。。

生活经验告诉我们,烧伤或者烫伤之后皮肤上经常会出现水泡,专业的称呼其实是“水疱”。实际上,出现这个水疱也代表着这一次烧伤已经达到了Ⅱ度烧伤的水平。

临床中,根据对皮肤的损伤程度不同,采用三度四分法将烧伤分为不同的级别。

法医学中因为还有能将尸体炭化,所以是四度。

Ⅰ度烧伤最轻,简单理解就是局部的皮肤发红。

Ⅱ度烧伤也叫水疱性烧伤,顾名思义就是会出现标志性的烧伤水疱。Ⅱ度烧伤中又分为浅Ⅱ度和深Ⅱ度,水疱主要出现的浅Ⅱ度中。

烧伤水疱的形成原因是高温破坏了一部分皮肤结构,之后渗出的组织液或者因为受热扩张的血管内渗出液积聚在损伤的部位,形成了水疱。这种水疱的形成与受到热力损伤的皮肤组织存在活力有关,换言之就是“皮肤组织是活的”。

人作为一个复杂的整体,整体性的死亡可以将没有呼吸心跳作为标志,但是整体死亡不意味着身上的零零碎碎就一起一个时间瞬间都死掉了。

有的细胞,器官功能可以在人整体死亡之后还存活几分钟,几小时。个别的甚至十几小时后还能观察到细胞还活着。。。。

所以,对于死亡不久的尸体,这水疱也还是能够形成的。只是如果更精细的检查,比如通过显微镜观察,在水疱周围不会出现明显的炎症反应了。

另外一个重要的原因是水疱形成是组织液的积聚,这需要在损伤的周围还存在一定完好的组织,也就是损伤要比较局限,或者是轻重不一。不然汤汤水水的都淌光了,那也没有水疱可言了。

比如,烤肉的时候一般都是肉片了。。。。组织液有吗?肯定有,但是一出来就烤干了或者流掉了。。没地方积攒嘛。

另外,油炸火烤食物的程度一般肯定是大于Ⅱ度烧伤的了,所以那些再看到的泡泡,更多的应该已经是焦化甚至是炭化了。

哦豁。。。。

好像把好好的烧烤一说成烧伤。。。感觉顿时失去了所有胃口。

今天又减肥了。╮(╯-╰)╭

查看知乎讨论
浏览量: 24

科学家将新发现的螃蟹命名为「提莫」,它有哪些特征?它的发现对于海洋生物多样性研究有哪些意义?

头图

这次以电子游戏中的人物 / 形象给新物种命名不是第一次,在 2020 年后,这种现象越发流行。

中国研究人员在西沙群岛和南沙群岛发现了这一新物种。这种新螃蟹名叫 Gothus teemo,属于 扇蟹科(Xanthidae ),全身呈乳白色,并带有棕色条纹。这与英雄联盟中的提莫非常相似,体型小巧且可爱。因此以 Teemo 命名。

以游戏中的角色命名的生物有很多种,其中游戏包括《Galaga》,《超级马里奥》,《塞尔达传说》,《街头霸王》,《宝可梦》,《生化奇兵》等。其中以宝可梦名字命名的动物最多,而所有以游戏角色命名的动物中,蜘蛛占比最大。

最早以游戏中的角色命名的动物在 2011 年,是以《宝可梦》中的独角虫(Stentorceps weedlei )命名的一种黄蜂。

2023 年,有两个以《塞尔达传说》中的形象命名的蜘蛛。

Orcevia yahaha“这个种加词是‘Yahaha’(也被称为‘Korok’)的同位名词,‘Yahaha’是游戏《塞尔达传说:荒野之息》中非常可爱的小精灵。Yahaha 经常躲在树干、灌木丛或岩石中,如果你找到它们,它们会说‘Yahaha!’并和你分享一些‘果实’作为礼物。

Orcevia bokoblin“该种名来自‘Bokoblin’,这是任天堂开发和发行的游戏《塞尔达传说:荒野之息》中的一只小猪怪兽。

male (315–317) and female (318) of Orcevia yahaha

2023 年,新加坡森林自然保护区发现了一种新蟑螂Nocticola pheromosa,该物种以出现在视频游戏系列第七代中的一种类似蟑螂的神奇宝贝芙洛美螂(Pheromosa) 命名,它是通过比较样本与婆罗洲的近亲的雄性生殖器的差异等方法发现的。

以皮卡丘命名的生物有三个:

一个是 2020 年发现的蜘蛛Epicratinus Pikachu这种好奇的蜘蛛栖息在巴西东北部的一些地区,它的发现者给它起了这个名字,因为它的外雌器(生殖器开口)的奇特形状有点像皮卡丘的圆脸,脸颊上有其特有的圆圈。

一个是 2021 年由林业杰发现的Alistra Pikachu 此处要@林业杰 oOOo ,欢迎提供图片。

以及在 2021 年描述的一种甲虫Hiperantha Pikachu,它也生活在巴西,不难想象他们为什么决定给它起这个名字,因为它的翅膀长达 21 毫米,和皮卡丘的耳朵一模一样。

被命名为喷火龙Chilicola Charizard的是一种生活在智利安第斯山脉地区的小型但非常有抵抗力的蜜蜂。根据互联网上流传的故事,它的发现者、加拿大科学家斯宾塞·K·蒙克顿(Spencer K. Monckton)会给它起这个名字,因为小时候,他是该系列的忠实粉丝,喷火龙是他喜爱的神奇宝贝。

2020 年,东新墨西哥大学医生达伦·波洛克和澳大利亚国立大学博士生萧云发现了澳大利亚昆士兰州特有的三种甲虫。萧是宝可梦的忠实粉丝,以关东地区的三只传奇鸟的名字命名这三种甲虫:Binburrum Articuno、Binburrum Zapdos和Binburrum Moltres。

查看知乎讨论
浏览量: 37

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 语言习题测试

查看知乎讨论
浏览量: 30

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

头图

居里夫妇自从 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,搜索「混乱博物馆」,关注我们。

查看知乎讨论
浏览量: 29

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

头图

鸟(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]

查看知乎讨论
浏览量: 38

如何看待 HTTP/3 ?

头图

互联网通信发展史其实是人类与 RTT 斗争的历史,详情请继续阅读下文。

没有多少基础的读者可以先阅读:

在浏览器地址栏输入一个 URL 后回车,背后会进行哪些技术步骤?

为了更好理解文章,需要解释一下什么是 RTT?

RTT是Round Trip Time的缩写,通俗地说,就是通信一来一回的时间。

TCP 建立连接时间

最早大家使用 TCP 来运输 HTTP,TCP 想必大家很熟悉了,需要三次握手,建立了 TCP 虚拟通道,那么这三次握手需要几个 RTT 时间呢?

一去 (SYN)

二回 (SYN+ACK)

三去 (ACK)

相当于一个半来回,故 TCP 连接的时间 = 1.5 RTT 。

HTTP 交易时间

这意味着,用户在浏览器里输入的网址 URL,直到时间流逝了 1.5RTT 之后,TCP 才开始运输 HTTP Request,浏览器收到服务器的 HTTP Response,又要等待的时间为:

一去(HTTP Request)

二回 (HTTP Responses)

故 HTTP 的交易时间 = 1 RTT

那么基于 TCP 传输的 HTTP 通信,一共花费的时间总和:

HTTP 通信时间总和= TCP 连接时间 + HTTP 交易时间 = 1.5 RTT + 1 RTT = 2.5 RTT

安全加密通信

随着互联网的爆发式增长,人类发现完全明文传输的 HTTP 通信很不安全。做为 OSI 七层参考模型的现实实现的 TCP/IP 协议,在设计之初没有考虑安全加密的环节。

互联网先驱Netscape公司,创造性发明了SSL(Secure Socket Layer),SSL 位于 TCP 与 HTTP 之间,做为 HTTP 的安全供应商,全权负责 HTTP 的安全加密工作。

IP / TCP / SSL / [HTTP]

各个通信模块之间的站位如上所示,将 HTTP 用[ ]括起来,表示 HTTP 被 SSL 安全加密了。

随着 SSL 的名气攀升,互联网标准化组织 IETF,觉得 SSL 是一个好东西,就拿来用了。

但 SSL 最初只是用于加密 HTTP 的,IETF 觉得这是一个硬伤,为什么不能用来做为所有应用层协议的安全供应商呢?来传输邮件、文件、新闻等等。实现这一点很简单,只要在协议里增加一个 Application Protocol 类型字段。

在 Application Protocol 有一个类型是“IP”, 意味着 TLS 不仅可以运输应用层协议如 HTTP、FTP,还可以运输 IP,这就是Cisco Any Connect的应用场景。

TLS (Transport Layer Security)

于是,IETF 在 SSL 3.0 版本的基础上,重新设计并命名了这个协议,其全新的名字为TLS,最初的版本为 1.0 版本。从其名字就可以看出,其核心使命就是保证传输层的安全。各个通信部门成员的占位与 SSL 占位一致:

IP / TCP / TLS / [HTTP]

到目前为止,浏览器支持的 TLS 版本为 TLS 1.0、1.1、1.2,当然版本越高越成熟、越安全。

HTTPS

通常将 TLS 安全保护的 HTTP 通信,称之为 HTTPS,以区别于没有 TLS 安全防护的 HTTP 明文通信。

交待了上文的背景知识,还是要回到本文的主题,来看看自从引入了 TLS 安全防护,看看 HTTPS 通信的 RTT 增加到了多少?

TLS 1.2

以 1.2 版本为例,看看 HTTPS 通信一共要消耗几个 RTT 时间?

1. 浏览器给服务器发送的 Client Hello 消息(一去)

首长好,我支持 1.2 版本,加密套件列表 1、2、3…,以及我的随机码 N1,请出示您的证件。

2. 服务器给浏览器发送的 Server Hello 消息(二回)

同志们好,那就 1.2 版本通信吧,加密套件我选用 1,我的随机码 N2,ECDHE 密钥交换素材 2,这是我的证件。

同志们辛苦了!

3. 浏览器给服务器发送的 Key Exchange 消息(三去)

为人民服务! 嘴里虽这么说着,私下还要偷偷验证首长的证件是否伪造的。

首长证书验证成功之后,还要给首长会话呢?会话内容如下:

首长辛苦了! 我的 ECDHE 密钥交换素材 1,接下来我发给您的消息都要加密了(Change Spec)。

从这以后,双方的 HTTP 通信将使用 TLS 加密了。一共花费了 1.5 个 RTT 时间。

让我们来计算一下整个 HTTPS 通信花费的时间总和:

HTTPS 通信时间总和 = TCP 连接时间 + TLS 连接时间 + HTTP 交易时间 = 1.5 RTT + 1.5 RTT + 1 RTT = 4 RTT

如果浏览器与服务器物理距离很近,RTT < 10 ms,即使 4 RTT 最大也不过 40 ms 的时间,用户压根感觉不到慢。

如果浏览器与服务器相隔上万公里,一个 RTT 时间通常在 200ms 以上,4RTT 时间通常在 1 秒以上,用户会明显感觉到网速慢了。

HTTP 1.x

和很多人想象不一样的是,浏览器从服务器获取的一个页面,通常由很多资源链接所组成。

服务器给浏览器推送的第一个页面,页面里通常嵌入了图片资源文本链接、以及动态页面资源链接、或第三方网站的链接资源,还需要浏览器根据这些文本链接内容,去链接所对应的服务器,继续下载链接所对应的内容。

浏览器通常采用的流程是,重新建立一个 TCP 连接、TLS 连接、HTTP 交易。

这又是一个漫长的 4RTT 等待过程,用户看到浏览器完整页面的时间为

完整页面加载时间 = 4RTT *2 = 8RTT

HTTP /2

自然有人会问,既然第一次页面与第二次页面都是同一个网站服务器,为何第二次页面要重新建立一个 TCP 连接,一个 TLS 连接?

如果重用第一个 TCP 连接,那么就少了 1.5 RTT + 1.5 RTT = 3 RTT 的时间。

这是一个好主意,就是用户的多个 HTTP Request 请求,使用同一个逻辑通道进行运输,这样会大大减少重新建立连接所花费的时间。

但是,这样会带来一个副作用,多个 HTTP 流使用同一个 TCP 连接,遵守同一个流量状态控制。只要第一个 HTTP 流遭遇到拥塞,剩下的 HTTP 流压根没法发出去,这就是头部阻塞(Head of line Blocking)。

既然 TCP 不好用,那为何要吊死在 TCP 这一棵树上呢?

外面的世界很精彩,到外面的世界逛逛。

QUIC(Quick UDP Internet Connection)

逛下来的感受是,UDP 不需要连接,不会带来附加的 RTT 时间,UDP 是一个好的合伙人被 HTTP /2 拉上了贼船,各合伙人的站位如下:

IP / UDP / QUIC

这个就是 Google 开发 QUIC 协议,QUIC 协议集成了 TCP 可靠传输机制、TLS 安全加密、HTTP /2 流量复用技术,其页面的加载时间为 2.5 RTT 时间。

此外,完成 QUIC 交易的连接的 Session ID 会缓存在浏览器内存里,如果用户再次打开该页面,无需建立 TLS 连接,直接使用缓存 Session ID 对应的加密参数,服务器可以根据 Session ID 在缓存里查找对应的加密参数,并完成加密。

换句话说,重连 TLS 连接是一个 0 RTT 事件,用户所要等待的页面加载事件 = HTTP 交易事件 = 1 RTT。

HTTP /3

这一次 IETF 又觉得 QUIC 是一个好东西,但是希望 QUIC 不仅可以运输 HTTP,还可以运输其它协议,把 QUIC 与 HTTP 分离,最终各合伙人的占位如下所示:

IP / UDP / QUIC / HTTP

这样整体的页面加载时间为 2 RTT。

TLS 1.3

IETF 的 QUIC 标准集成了 TLS 1.3 版本,1.3 版本更简练,建立 TLS 连接不再需要 1.5 RTT,而只需要 1 RTT,是因为浏览器第一次就把自己的密钥交换的素材发给服务器,这样就节省了第三次消息,少了 0.5 个 RTT 时间。

页面的整体加载时间 = TLS 1.3 连接时间 + HTTP 交易时间 = 1RTT + 1RTT = 2 RTT

重连页面的加载时间 = HTTP 交易时间 = 1 RTT

上文协议的进化过程就是人类与 RTT 斗争史,目标是减少用户等待页面加载时间、同时保证用户看到的页面安全,没有在传输过程中被偷窥、篡改。

HTTP /3 所带来的挑战

99%+ 以上的手机移动终端、电脑终端,都使用私有 IP,都需要 NAT 设备来完成私有 IP 与全球 IP 的转换。这意味着 NAT 设备通常会记忆用户的通信状态,一旦用户完成了通信,NAT 设备会释放这些记忆。

对于基于 TCP 的 HTTP、HTTPS 传输,NAT 设备可以根据 TCP 报文头的 SYN / FIN 状态位,知道通信什么时候开始,什么时候结束,对应记忆的开始、记忆的结束。

但是基于 UDP 传输的 HTTP/3,NAT 设备收到流量会知道连接什么时候开始,但是却无法知道流量什么时候结束。

NAT 设备的记忆如果短于用户会话时间,则用户会话会中断。

NAT 设备的记忆如果大大长于用户会话时间,则意味着 NAT 设备的端口资源会白白被占用!

最直接的解决方案是,在 QUIC 的头部模仿 TCP 的 SYN/FIN 状态,让沿途的 NAT 设备知道会话什么时候开始、什么时候结束。但这需要升级全球所有的 NAT 设备的软件!

另外一个可行的方案是,让 QUIC 周期性地发送Keepalive消息,刷新 NAT 设备的记忆,避免 NAT 设备释放自己的记忆。

最后留给读者一个思考题,为何 HTTP/3 不直接站在 IP 身上,而是站在 UDP 身上?

查看知乎讨论
浏览量: 29

猫狗吃巧克力会中毒,那么老鼠吃巧克力会不会中毒呢?

头图

谢邀

(声明:本回答下所涉及图片,代谢通路图来自 KEGG,与视觉中国无关;本回答中涉及所有实验 / 计算数据均来自权威科学网站,请勿擅自使用自家猫 / 狗 / 人 / 其他动物做实验,后果自负;本实验中所有动物均默认为是成年健康个体,怀孕 / 幼年 / 生病 / 服药的个体可能更加脆弱)


先亮结论:会,但是比较少见。

老规矩,“太长不看”派道友请直接翻到最后渡劫。


首先要明确的是,巧克力的毒性,主要来自于其含有的咖啡因(caffeine)和可可碱(theobromine)。这两种物质均为植物的次级代谢产物,据传说这些东西进化出来的本意就是想要毒死动物……但是很不幸地是人类对这玩意耐受能力还挺强。

咖啡因和可可碱的主要致病 / 致死机理是其在 CYP1A2(一种细胞色素 C)和黄嘌呤氧化酶的共同作用下,在肝细胞中最终代谢为各种甲基尿酸。甲基尿酸是尿酸的类似物,但是因为体积变大了,因此会占用尿酸的排出途径,但是难以被排出,最终导致累积毒性造成急性肝损伤……

为了说明一下它们的详细代谢过程,我借用了一下著名的组学信息数据库,日本的 KEGG(KEGG: Kyoto Encyclopedia of Genes and Genomes)里边的代谢通路图,以下三张分别是猫、狗、人、大鼠的代谢。只有标有绿色方框的才可以走。方框里写有数字的是酶的编号,1.17.3.2 是黄嘌呤氧化酶(Xanthine oxidase)。

猫的咖啡因 / 可可碱代谢通路,只有标有绿色的通路是可以进行的。
狗的
人的
大鼠

图片中间的是可可碱,它右边的是咖啡因。大家可以试着沿图上给出的路线走一走,最后走到的基本都是以“methyluric acid(甲基尿酸)”结尾的产物,这就是咖啡因 / 可可碱的毒性机制。


那么, 这种东西的毒性到底有多强呢?因为巧克力里边咖啡因含量很低,所以以下我们就拿可可碱说事儿了。在毒理学上,一般用 LD50 来表示物质的急性毒性。LD50 意为,在这个剂量下,在大规模的实验中,实验群体中有 50%的个体死亡,通常表示为 mg/kg bw(毫克每千克体重)。不同的物种,不同的摄入方式下 LD50 可能有较大区别。

那么,咖啡因和可可碱对猫、狗、人、鼠的 LD50 值如下(因为不能用人做实验,所以人的数值是以其他动物作为基础而推测出来的):

参考资料:

Material Safety Data Sheet #1

Theobromine

可以看到的是,人和大鼠对于咖啡因的耐受能力略高于猫狗,而对可可碱的耐受能力则强于猫狗 3-5 倍,因此人和大鼠相对猫狗而言不容易中毒。但是实际中我们观察到的巧克力中毒事件发生率则是狗大于其他三种物种。为什么呢?

因为猫有基因缺陷,尝不到甜味,所以不爱吃巧克力。

因为人体重太大了,等人中毒了,早就撑死了。

因为养耗子的人太少了,你看到一个死耗子,躲开都来不及,还关心它怎么死的么?

所以,综上,狗是最特么容易被巧克力毒死的。


不过,话都说到这份儿上了,不如算算,多少巧克力能毒死一个正常猫 / 狗 / 人 / 大鼠?

我在一篇文献(https://onlinelibrary.wiley.com/doi/abs/10.1111/j.1365-2621.1980.tb02603.x)里看到过,一般的甜巧克力,平均含有 0.46%的可可碱和 0.07%的咖啡因。对于猫狗,咖啡因的毒性是可可碱的 2 倍;对于人和大鼠则是 5 倍,而这二者又使用相同或相似的代谢通路。因此我们不妨做一个简化计算,每一份咖啡因,对于猫狗相当于两份可可碱,对于人鼠则是五份,以下内容统一使用可可碱计算:

则 100g 巧克力中,含有 0.6g(猫狗)或 0.81g(人鼠)可可碱。按照如下标准体重,可以计算出达到 50%致死率所需要的巧克力质量:

猫:5kg,需要 167g 巧克力

(小型)狗:5kg,需要 250g 巧克力

(中型)狗:15kg,需要 750g 巧克力

(大型)狗:40kg,需要 2000g 巧克力

人:60kg,需要 7500g 巧克力(15 斤,撑死你)

鼠:0.2kg,需要 25g 巧克力

需要注意的是,以上计算的数据来自市面上巧克力的平均值,有些巧克力的咖啡因 / 可可碱含量明显较高,会造成致死量较低。一只 200g 的大鼠,其半数致死量为 25g 巧克力。但是通常一只大鼠一天的饭量只有 10g 左右……所以只能说,一只大鼠如果某天饭量打开,并且食用了咖啡因 / 可可碱含量比较高的巧克力,还是有可能死的吧。


“太长不看”派道友此处渡劫:

  1. “巧克力中毒”中的主要毒素是咖啡因和可可碱,只要摄入剂量足够大,猫,狗,老鼠和人都会中毒。但是相对而言,人和老鼠对于咖啡因 / 可可碱的耐受能力比猫狗大一点。通常情况下,老鼠不太会被巧克力毒死,但是极端情况下也可能出现这类情况。
  2. 现实中死于巧克力的一般都是狗,因为猫尝不到甜味,所以不爱吃巧克力。人在被毒死之前先会被撑死。至于老鼠……死了个耗子你们还会谁仔细观察吗。
查看知乎讨论
浏览量: 26

文章分页

上一页 1 … 4 5 6 … 20 下一页

Copyright © 2024 51蛙吖蛙 – 3D社交空间