你見過的最想笑的,最奇葩的,最逗逼的代碼是什麼?
如題,什麼語言的代碼都行
我曾經任職的一家公司,規模不小,幾百號人吧。拳頭產品是一款MOBA遊戲(及其衍生品)。這款遊戲使用C++/lua開發,其中C++代碼扮演的是引擎的角色,其他功能全部是使用lua實現的。這是我這輩子見過的最奇葩的代碼庫。它前後歷經幾百人寫就,沒有規約,沒有架構,沒有文檔,沒有單元測試,沒有code review,沒有profiling,沒有分支卻被五六個在它之上構建的項目使用。它依然屹立不倒,至今戰鬥在前線,支撐著一個年收入過億的遊戲。
它簡直就是一個帕奇維克。
這個codebase的作者們在公司的官方定位是「腳本策劃」(後改名為「腳本程序員」),在鼎盛時期,這個腳本策劃群有40人之眾。招聘時只對應聘者有最基本的程序基礎要求,大概就是大學C語言的水平。這樣的大背景把這個codebase變成了一個極好的工程範例,它是一本worst-practise的百科全書。裡面的代碼雖然不像很多答主所列舉的那些精心設計的奇葩代碼引人發笑,卻有著深刻的現實意義。
- 整個codebase有30MB左右,其中至少10MB是手寫的,剩下的是自動生成的。以下都只說手寫的代碼。
- 最大的一個文件(在我手上的版本,好幾年了)有763KB,包含近10000行代碼。
- 代碼里有迷之全局變數a、b、c、d、aa、bb、cc、dd、aaa、bbb、ccc、ddd等等等等,據說是上古時期CTO寫就的,變數的值也是從引擎傳遞出來的,所以沒人敢改。至於它們究竟是什麼含義,誰知道呢,反正沒有文檔,全靠口口相傳。
- 各種用於測試互斥二態的API(或者說,應該返回布爾值的API),有的返回0/非0,有的返回nil/非nil,有的返回false/true……後來大家都搞不清楚了,所以普遍的做法是在調用這種API時把這三種情況都判斷一遍(實際上對於lua來說只要判兩種,因為if(nil)和if(false)是等價的)。
- 用全局變數還是局部變數,主要看心情。命名空間/module是沒有的,所有函數都是全局函數。有一次我隨手看了一下,全局變數幾萬個吧(lua里函數也算變數)。
- 有一次,公司決定出國際版,要對整個遊戲做英文本地化。但是遊戲內的所有文本都是寫死在腳本里的,於是派著名腳本策劃W把整個腳本代碼里的文本過一遍。W熬了好幾個夜,終於完成了這一浩瀚的工程。後來在codebase里,每一處文本字元串後面都跟了一條注釋:
-- W到此一游
一共3000多處。
- 成百上千行的函數比比皆是,其中的佼佼者,我隨手用偽代碼寫個例子:
function castSkill(skillId)
if 不是普通攻擊(skillId) then
-- 釋放技能的邏輯,幾百行
return
endcastNormalAttackSkill(skillId)
endfunction castNormalAttackSkill(skillId)
-- 普通攻擊的邏輯,幾百行
end
你知道當初看到castSkill函數的最後一句時,我的心情是崩潰的。
- 引擎端為腳本端開放了一個廣受好評的技能廣播API。具體思路是,腳本告訴引擎,我放了一個ID為XXX的技能,引擎再告訴伺服器,伺服器通知所有客戶端,所有客戶端的腳本端都會收到一個參數為XXX的回調。
後來大家覺得這個API太好用了,於是開發商店功能時,開始用這個API來買東西。具體來說,我買了個藍瓶,相當於放了一個ID為YYY的技能,其他客戶端收到這個YYY的回調後,幫我的道具欄里加個藍瓶。為了避免和技能起衝突,約定ID為10000以下的是技能,10000以上是買道具。
後來,大家又心照不宣地使用這個API實現了諸多消息廣播功能,並約定了一個複雜的ID分配表——還是那句話,沒有文檔,全靠口口相傳。 - 你知道lua可以寫面向對象代碼嗎?只不過需要自己實現繼承結構,很簡單,用metatable就可以。整個codebase里至少有三種不同的OO實現,以及相同數量的人分別使用過它們。剩下的所有代碼都不是OO的。
- 何止是OOP,AOP這麼先進的東西都有人能熟練應用。有一次發版本後感覺很卡,追查了一下代碼,發現有人搞了點黑科技,由於涉及到太多lua的專有概念,所以我用偽代碼描述一下:
遍歷所有全局變數,對於每個全局變數var:
如果var是函數,且名稱以UI_開頭:
將這個函數替換為一個新的函數,新函數先打個stacktrace到log里,然後執行原函數
妥妥的AOP。你以為你調用的是引擎給你的API,其實早就被別人包裝了不知道好幾道了,底褲都給你看光了。而且像lua這種代碼可以裸寫在全局空間(甚至不需要包裝為函數)的語言,這種包裝神出鬼沒,說不定藏在哪個犄角旮旯里呢。
- 一種被廣泛使用的編碼模式:
function foo(arg)
local defaultArg = {}
-- 一大段初始化defaultArg的代碼,幾行到幾十行不等
arg = arg or defaultArg -- 這句話的意思是,如果arg為空,把defaultArg賦值給arg
-- ...
end
更新,答記者問:這裡並不是說or的用法不對,而是arg不為空時,defaultArg的大段初始化代碼都白白執行了。
- 另一種被廣泛使用的模式:
for i = 1, 9, 1 do -- for(var i = 1; i &<= 9; i+=1) if i == 1 then -- .... end if i == 2 then -- .... end -- ... end
-- 08年12月9日注釋,09年12月9日之後看到這兒的兄弟請幫忙刪除掉
-- (被注釋的大段代碼)
function ChangeKeytoString(i)
if i == 39 then
return "A"
elseif i == 40 then
return "B"
-- ...
end
end
if target_id == 9999 then
target_id = -1
elseif target_id == 9998 then
target_id = -5
end
-1是什麼,-5又是什麼?好奇心害死貓,要麼舔著臉去問這裡資歷最老的人(他也不一定記得),要麼準備好咖啡,今天晚上就睡這兒了吧。
- 奇葩命名層出不窮,我就舉一個最喜歡說的,有個技能叫吸血,在代碼里的命名是suckBlood。
更新,答記者問:比較好的命名應該是life drain(生命汲取,「吸」其實更像是「汲」的通假字,並不是代表吮吸這個動作),或者如 @Zhifan Yang 所說:lol裡面物理吸血叫life steal,法術吸血叫spell vamp。
先寫到這裡……我只是隨手翻了兩個文件的代碼而已……唉滿滿的都是回憶啊。
想不起來哪裡看到的了。。
public static DateTime getTomorrowDate()
{
Thread.Sleep(24*60*60*1000);
return DateTime.Now;
}
==========================
評論裡面有人說睡排序,也是神搞笑。
int main(int c, char **v)
{
while (--c &> 1 !fork());
sleep(c = atoi(v[c]));
printf("%d
", c);
wait(0);
return 0;
}
from wiki: http://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort
//拼寫容錯
#define ture true
#define flase false
#define viod void
你們那些都弱爆了
點個贊吧
在餐館點菜,點了一個干鍋田雞 由於A不能吃辣椒 所以只有把這個菜取消 於是乎負責寫菜名的B很流利的在菜單上加了一個// 成了這樣: // 干鍋田雞
重點是我們當時看見了還覺得挺正常,沒有一個人提出來。。。。。。。。
上次隊友寫代碼,用到數組的時候,定義了一個 int arr[110];
需要另一個數組的時候,又定義了一個 int brr[110];
brr……
經評論區朋友指出,這個是傳說中的複雜度為 O(n) 的排序演算法 sleep sort:
對一個有 N 個元素的整型數組 arr 排序,開 N 個線程,每個線程延時對應的 arr 的數值的秒數後輸出,大概如下:
import threading
import time
def ouput(x):
time.sleep(x)
print x
arr = [5, 2, 3, 4, 1]
threads = []
for i in arr:
t = threading.Thread(target=ouput, args=(i,))
t.start()
threads.append(t)
public enum ColorType
{
Green, // 綠色
Hong, // 紅色
}
//......
this.curColortype= ColorType.Hong;
......
毫無違和感! 英語和漢語的激烈碰撞,一時愣是沒讀懂代碼,「Hong」為何物,你看注釋才恍然大悟!犀利
可能是綠的拼音(lv) 有點像等級,所以為了防止歧義,用了Green!贊一個!
我當年寫過一個在windows下deltree的程序,少寫了空參數判斷,導致沒有輸入參數的時候會 deltree 。後來發現這個錯誤以後以自嘲的心態發到了CSDN供大家批判,結果好多人拿來就運行了……
離職前不要忘記提交的代碼
源地址:https://gist.github.com/aras-p/6224951
// 關鍵字替換. 好像會很容易被人發現欸!
#define struct union
#define if while
#define else
#define break
#define if(x)
#define double float
#define volatile // this one is cool
// 聽說你很喜歡數學?
#define M_PI 3.2f
#undef FLT_MIN #define FLT_MIN (-FLT_MAX)
#define floor ceil
#define isnan(x) false
// 沒關係,別擔心,一定能順利運行的,嗯!
#define true ((__LINE__15)!=15)
#define true ((rand()15)!=15)
#define if(x) if ((x) (rand() &< RAND_MAX * 0.99))
// 字元串和內存操作永遠是程序員的好朋友
#define strcpy(a,b) memmove(a,b,strlen(b)+2)
#define strcpy(a,b) (((a 0xFF) == (b 0xFF)) ? strcpy(a+1,b) : strcpy(a, b))
#define memcpy(d,s,sz) do { for (int i=0;i&
是時候祭出這段代碼了。https://github.com/asgrim/year
return a == b ? a : b;
當年初學C語言,老師要求用*列印一個菱形,大概就這個:
*
**
***
****
*****
****
***
**
*
然後當時有人老老實實用循環,有人用遞歸,但是我舍友說他們那套太複雜了。於是我看了他的代碼…
#include 「stdio.h」
int main()
{
printf(" *
**
***
*****
******
****
***
**
*
");
return 0;
}
果然方便又簡潔,還一目了然…
—————————————————
很多知友說這確實是最簡單快捷的程序,沒錯,這個簡單易行。可是當時老師的目的是讓你掌握基礎的演算法,在這種題上確實不應該投機取巧…例如高中學二次方程,x^2-3x+2=0,你當然可以用代入法輕鬆解出答案是1和2,但是這對你並沒有幫助,二次方程你依然是不會的,改一個參數後,你還能一個一個代入嗎?
就在昨天下午!!對,這TMD不是拼寫錯誤!!他是真的需要最後一個元素的Value.
語言來自世界上最好的語言。
mian
#include studio.h
別問我為什麼打不出符號,我也不知道
(捂臉)
Source: https://xkcd.com/221/
從另外一個帖子里轉過來的
try{
//這段代碼是有錯的,可這傢伙不debug
}
catch(Exception e){
//正常功能放在這,要報錯才可以執行
}
當時真笑到我想哭…
——————更新——————第一次回答表達不清,修改了說明。
大家知道M_PI_2嗎?曾有多少英雄好漢以為那是pi * 2
推薦閱讀:
※Microsoft BASIC 源代碼公布,如何評價比爾·蓋茨寫代碼水平?
※晚上腦子裡也想著bug,睡不好怎麼辦?
※作為程序員,你有哪些正在做的個人項目?
※機器學習數據挖掘類工程師平時主要的工作內容是怎樣的?
※上古時期的程序員都有哪些當今普通程序員無法想像的神級操作?