在 C 語言面試中,「請定義一個宏來表示一年的秒數」是一道極具代表性的經典題目。乍看之下,答案似乎觸手可及:#define SECONDS_PER_YEAR 60*60*24*365。然而,這道題的真正考點並非計算能力,而是考察候選人對工程嚴謹性、單位換算以及邊界條件的思考深度。
許多教材給出的「標準答案」如下:
#define SECONDS_PER_YEAR 60*60*24*365UL
這種寫法的優點顯而易見:
UL (Unsigned Long) 明確指定了常量類型,避免 16 位系統上整型溢出(365×24×3600 = 31,536,000 超過 16 位有符號整數上限 32,767)。但這真的是正確答案嗎?
面試官往往會追問:「每年的秒數真的相同嗎?閏年怎麼辦?」
這時候,單純的 365 天模型就崩潰了。我們必須區分兩個天文學概念:
| 年份類型 | 定義 | 長度 |
|---|---|---|
| 恆星年 | 地球繞太陽公轉 360° 所需時間 | 365 天 6 時 9 分 10 秒 |
| 回歸年 | 太陽連續兩次回到春分點的間隔(四季循環基準) | 365 天 5 時 48 分 46 秒 (約 365.2422 天) |
現行公曆(格里曆)採用回歸年,閏年規則為:四年一閏,百年不閏,四百年再閏。400 年共 97 個閏年,平均年長 = 365 + 97/400 = 365.2425 天,與回歸年極其接近。
若面試要求「按回歸年精確計算」,可拆解為天、時、分、秒:
// 回歸年:365天 5時 48分 46秒 #define SECONDS_PER_TROPICAL_YEAR (365*24*60*60 + 5*60*60 + 48*60 + 46)UL // 恆星年:365天 6時 9分 10秒 #define SECONDS_PER_SIDEREAL_YEAR (365*24*60*60 + 6*60*60 + 9*60 + 10)UL
更進一步,若採用高精度值 365 天 5 時 48 分 45.975456 秒,則需引入浮點數:
#define SECONDS_PER_YEAR_PRECISE 31556925.975456
此時 float (32 位,約 7 位有效數字) 已不足夠精確,建議使用 double。
在大多數業務系統中(如計費、日誌時間戳),並不需要天文級精度,而是遵循「日曆年」:平年 365 天,閏年 366 天。此時宏定義退化為最初的簡單形式,但必須配合運行時閏年判斷函數使用:
#define SECONDS_PER_COMMON_YEAR 31536000UL // 365*24*3600
#define SECONDS_PER_LEAP_YEAR 31622400UL // 366*24*3600
inline bool is_leap_year(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
UL 後綴。下次遇到這道題,不妨微笑著反問一句:「您想要的『一年』,是哪種年?」