用 C 語言寫 Android 版本的 Flappy Bird

也是在 Hacker News Daily 上看到的專案,用 C 寫的 Android 版本的 Flappy Bird,而且支援度還頗廣的,Android 5.1+ 都可以執行:「VadimBoev/FlappyBird」。

看起來也因為這篇的關係,用 C 寫 Android 程式的計畫也被再次貼到 Hacker News 上:「Rawdrawandroid – Build Android apps without any Java, in C and Make (github.com/cnlohr)」,專案在「cnlohr/rawdrawandroid」這邊,我找了一下之前提過:「用 C 與 Makefile 開發的 Android 專案」。

用 C 寫的好處就是可以很小,像是這次用 C 寫 Flappy Bird 的 Android 版本直接包出 <100KB (對,<0.1MB) 的 ARM 平台 binary package (看起來是 32bit + 64bit 的雙版本),這種大小的遊戲已經很少見了...

不過開發起來又是另外一回事了,應該算是作者的興趣?

C++ 實作高頻交易程式的技巧

看到「C++ patterns for low-latency applications including high-frequency trading (arxiv.org)」這篇,原文是 2023 年九月上傳到 arXiv 的 paper:「C++ Design Patterns for Low-latency Applications Including High-frequency Trading」。

有點 LLM 的文字感,在 Hacker News 上有人有提到這點,另外有一些圖表的錯誤,像是這兩份資料可以發現對不上,label 有標錯:

主要還是看列出的方法在自家專案上嘗試,不能直接把他們的數據拿來參考,在自家專案還是得在自家專案上面 benchmark 才知道有多少效益。

不過裡面提到蠻多有趣的作法,很多都是「知道」但沒有放在心上的...

用 Astrometa DVB-T2 收數位無線電視台 (DVB-T)

以前用的 USB 電視棒壞掉了,去網拍上找了一隻新的來用,翻了一下跟 LinuxTVWiki 上的 Astrometa DVB-T2 這頁的圖片一樣 (2014 版本的圖):

先講一下重點,如果你買到的 USB 電視棒跟我一樣,應該可以看到兩個 source 可以收 DVB-T,而這兩個 source 都可以測試看看,在我家裡測試 Sony CXD2837ER 的收訊明顯好很多:

另外順便一提無關緊要的事情,本來在查資料的時候以為是 2013 的古董版本,但研究了一會兒發現 2013 版的「DVBT2」字比較大,所以不是 2013 版的:

插入到 Ubuntu 的時候可以看到幾個有趣的東西:

[Sat Dec 30 11:59:49 2023] usb 1-6.3: DVB: registering adapter 0 frontend 0 (Realtek RTL2832 (DVB-T))...
[Sat Dec 30 11:59:49 2023] dvbdev: dvb_create_media_entity: media entity 'Realtek RTL2832 (DVB-T)' registered.
[Sat Dec 30 11:59:49 2023] usb 1-6.3: DVB: registering adapter 0 frontend 1 (Sony CXD2837ER DVB-T/T2/C demodulator)...
[Sat Dec 30 11:59:49 2023] dvbdev: dvb_create_media_entity: media entity 'Sony CXD2837ER DVB-T/T2/C demodulator' registered.

意外的發現有兩個支援 DVB-T 的晶片,首先是 Realtek RTL2832 有被抓到,然後被註冊到 /dev/dvb/adapter0/frontend0 這邊。

Realtek 官網上只翻到了 RTL2832U 的資料,裡面比較有趣的是支援了 ISDB-T,不過如果在日本的話還需要 B-CAS 才能解:

Includes ISDB-T(SBTVD-T) 1-Seg

另外 RTL2832U 也支援 FM:

Includes Radio Support (FM/DAB/DAB+)

而第二個的 Sony CXD2837ER 被註冊到 /dev/dvb/adapter0/frontend1 這邊,另外在 LinuxTVWiki 可以看到 CXD2837ER 只被用在了 2018 版本,而且在外觀的部分提到了「or same as 2014 or 2017 revision」,所以看起來手上的版本應該是 2018 版的,但是殼長得跟舊的一樣。

翻了 Sony CXD2837ER 的 datasheet,可以看到支援 DVB-{T2,T,C}:

The Sony CXD2837ER is a combined DVB-T2 (incl.T2-Lite), DVB-T and DVB-C demodulator

看起來是為了 DVB-T2 而放進來的?不過台灣目前還是用 DVB-T 就是了。

Anyway,目前用起來唯一的缺點是看電視的時候同時跑 dvb-fe-tool --femon -f 1 會造成畫面破格,這點要再看看怎麼解決,不過不是大問題...

從 Google Groups 送出來的 spam 數量稍微下降...

先前在「Google Groups 的巨量 spam」這邊提到從 Google Groups 倒進 usenet 大量的 spam,最近看起來稍微緩解了一些。

這是 10/22 的量:

這是 10/29 的量:

可以看出來整體被 Perl filter 擋下來的量大幅降低了,在 comp.lang.c 也可以看出來 10/28 後似乎暫時停了...?

只能繼續觀察看看了...

Raspberry Pi 5 的一些細節出現了...

上一篇「Raspberry Pi 5」提到了一些來自 Raspberry Pi 官方的說明,後續各個媒體 (像是 YouTuber) 也都解禁放出不少資料可以參考了,其中電源的部分在「Answering some questions about the Raspberry Pi 5」這邊看到不認 USB PD 的 5V/5A 的問題,目前看起來是走獨規:

I also tested the Radxa USB-C PD 30W power adapter, which says it will output 5V at 5A, but the Pi only negotiates 3A with it right now. I've been in contact with Pi engineers and it seems like they have one on the way to test to see why it's not negotiating more.

另外看起來之後有機會支援 12V/2.25A (換算起來是 27W) 的充電頭,有機會透過韌體更新認得 PD?

I should also note the official adapter lists 12V at 2.25A output as an option, so maybe some future Pi could take that and run with it, for increased compatibility with more USB-C PD adapters (5V at 5A is a rarely seen, though it's an option in the spec).

不過即使走 5V/3A (15W),在一般的應用下是夠用了,到時候拿到來玩看看...

ClickHouse 弄了一個 C++ 寫的 ZooKeeper drop-in replacement:ClickHouse Keeper

Hacker News 上看到「ClickHouse Keeper: A ZooKeeper alternative written in C++ (clickhouse.com)」,原文是「ClickHouse Keeper: A ZooKeeper alternative written in C++」。

在 distributed coordination 這個領域目前應該是 etcd 比較知名,但 Apache ZooKeeper 畢竟算是元老,還是有不少應用程式會把 ZooKeeper 當作基礎建設在用。

因此 etcd 也包了一個 zetcd,可以用 etcd 當作底層結構,但提供 ZooKeeper API 的介面讓應用程式使用:

Serve the Apache Zookeeper API but back it with an etcd cluster

這次 ClickHouse 的人搞出一個用 C++ 寫的 ClickHouse Keeper,定位是 drop-in replacement,想要解決現有的應用程式遇到的記憶體資源問題。

從開頭的說明就可以看到著重在這塊:

up to 46 times less memory than ZooKeeper ​​for the same volume of data while maintaining performance close to ZooKeeper.

而對於新的應用程式,在開發時應該就不太會選 ZooKeeper 了,畢竟連 distributed lock 都得自己操作 znode 把功能疊出來 (像是官網很貼心的還提供了「ZooKeeper Recipes and Solutions」,裡面提供了 lock 的方法),而這種事情太累,用 etcd 方便太多...

AWS 官方推出了自己的 Amazon S3 FUSE 套件

看到「Mountpoint for Amazon S3」這個專案,AWS 自己推出了自己的 Amazon S3 FUSE 套件。Hacker News 上也有一些討論:「Mountpoint – file client for S3 written in Rust, from AWS (github.com/awslabs)」。

Amazon S3 的價錢比其他 AWS 提供的 storage 都便宜不少。以美東第一區 us-east-1 來說,S3 是 $0.023/GB,而 EBS (gp3) 要 $0.08/GB,即使是 EBS (st1) 也要 $0.045/GB。

S3 相較於 EBS 來說,多了 API call 的費用,所以對於不會產生大量 API call 的應用來說 (像是常常會寫很大包的資料到檔案裡),透過 FUSE 操作 Amazon S3 可以讓現有的套裝軟體或是程式直接跑上去。

另外一個常見的應用是讓套裝軟體或是現成的程式可以讀取 S3 的資料。

之前這類應用馬上會想到的專案是 s3fs-fuse,這個專案很久了,大家也都知道多人寫入的部份會是痛點。

這次 AWS 自己出來做的事情有點重工,看起來他想做的事情 s3fs-fuse 都解的差不多了,目前看起來唯一的賣點應該只有 Rust-based,但 s3fs-fuse 主要是 C++,其實也沒差到哪裡:

Mountpoint for Amazon S3 is optimized for read-heavy workloads that need high throughput. It intentionally does not implement the full POSIX specification for file systems.

目前專案還是 alpha release,不確定專案的方向到底是什麼...

calloc() 與 malloc() 的差異

前陣子在 Hacker News Daily 上看到的,原文是 2016 的文章:「Why does calloc exist?」,裡面講的東西包括了 implementation dependent 的項目,所以要注意一下他的結論未必適用於所有的平台與情境。

malloc()calloc() 的用法是這樣,其中 calloc() 會申請 countsize 的空間:

void* buffer1 = malloc(size);
void* buffer2 = calloc(count, size);

第一個差異是,count * size 可能會 overflow (而 integer overflow 在 C 裡面是 undefined behavior),這點除非你在乘法時有檢查,不然大多數的行為都還是會生一個值出來。

calloc() 則是會幫你檢查,如果會發生 overflow 的時候就不會真的去要一塊記憶體用。

第二個差異是 calloc() 保證會將內容都設定為 0,這點在 POSIX 的標準裡面是這樣寫的:

The calloc() function shall allocate unused space for an array of nelem elements each of whose size in bytes is elsize. The space shall be initialized to all bits 0.

但作者就發現 malloc() + memset() + free() 還是比 calloc() + free() 慢很多:

~$ gcc calloc-1GiB-demo.c -o calloc-1GiB-demo
~$ ./calloc-1GiB-demo
calloc+free 1 GiB: 3.44 ms
malloc+memset+free 1 GiB: 365.00 ms

研究發現是 calloc() 用了 copy-on-write 的技巧,先把所有的 page 都指到同一塊完全被塞 0 的記憶體,只有在真的寫到該段記憶體時,系統才會要一塊空間來用:

Instead, it fakes it, using virtual memory: it takes a single 4 KiB page of memory that is already full of zeros (which it keeps around for just this purpose), and maps 1 GiB / 4 KiB = 262144 copy-on-write copies of it into our process's address space. So the first time we actually write to each of those 262144 pages, then at that point the kernel has to go and find a real page of RAM, write zeros to it, and then quickly swap it in place of the "virtual" page that was there before. But this happens lazily, on a page-by-page basis.

但畢竟這是 implementation dependent,看看有個印象就好。

C 語言裡面的 ??! 符號

Hacker News Daily 上看到這個奇怪的知識:「What does the ??!??! operator do in C? (stackoverflow.com)」,原文在 Stack Overflow 上:「What does the ??!??! operator do in C?」。

這是 trigraph,在 C89 就有了,從 Rationale for International Standard—Programming Languages—C 這邊的 5.2.1.1 可以看到 trigraph 的歷史原因:

Trigraph sequences were introduced in C89 as alternate spellings of some characters to allow the implementation of C in character sets which do not provide a sufficient number of non-alphabetic graphics

而且是強制要求實做:

Implementations are required to support these alternate spellings, even if the character set in use is ASCII, in order to allow transportation of code from systems which must use the trigraphs. AMD1 also added digraphs (see §6.4.6 and §MSE.4).

其中遇到的問題就是當年得決定 C 可以用的 charset,得考慮到很多不同機器 charset 相容性的問題:

The C89 Committee faced a serious problem in trying to define a character set for C. Not all of the character sets in general use have the right number of characters, nor do they support the graphical symbols that C users expect to see. For instance, many character sets for languages other than English resemble ASCII except that codes used for graphic characters in ASCII are instead used for alphabetic characters or diacritical marks. C relies upon a richer set of graphic characters than most other programming languages, so the representation of programs in character sets other than ASCII is a greater problem than for most other programming languages.

然後就使用了 ISO/IEC 646 這個標準 (要記得 Unicode 1.0.0 是 1991 年才出現):

The solution is an internationally agreed-upon repertoire in terms of which an international representation of C can be defined. ISO has defined such a standard, ISO/IEC 646, which describes an invariant subset of ASCII.

The characters in the ASCII repertoire used by C and absent from the ISO/IEC 646 invariant repertoire are:

[ ] { } \ | ~ ^

後面就是定義 ?? 當作 escape digraph。

算是一個歷史產物,現在不太需要用到了...

歐盟 2024 年年底強制使用 USB-C 充電頭 (終於,iPhone...)

Hacker News Daily 上看到「EU Passes Law to Switch iPhone to USB-C by End of 2024」,裡面指到了歐盟的新聞稿:「Long-awaited common charger for mobile devices will be a reality in 2024」。

2024 年年底 (所以是 2025 年) 將強制手機與平板都使用 USB-C 充電頭,2026 年則是延伸涵蓋到筆電:

By the end of 2024, all mobile phones, tablets and cameras sold in the EU will have to be equipped with a USB Type-C charging port. From spring 2026, the obligation will extend to laptops.

終於定案公告了,之前傳言好久了...