有哪些能炫技的代碼寫法?
不用考慮實用性,並希望帶有注意事項。
用最少字元實現。如:
- Milo Yip:一行 Python 能實現什麼喪心病狂的功能?
- Milo Yip:如何用 C++ 在 10 行內寫出八皇后?
- Milo Yip:求大神這個圖案怎麼用 C 語言編寫?
- Milo Yip:如何用C++寫出一個19行空心的菱形圖案?
- 如何用 C 語言畫這個圖
- 九層循環怎麼寫
貼一個 GacUI實現C++反射 的代碼。一開始GacUI的代碼那麼大,就是因為當年還不能完全從XML產生出C++,沒辦法給你一個不鏈接這部分代碼的選擇。可見展開後尺寸驚人。當然現在都可以做到了。
先來看一下一個被反射的介面(這部分是一定會被鏈接的):
class IMethodInfo : public virtual IMemberInfo, public Description&
{
public:
virtual ICpp* GetCpp() = 0;
virtual IMethodGroupInfo* GetOwnerMethodGroup()=0;
virtual IPropertyInfo* GetOwnerProperty()=0;
virtual vint GetParameterCount()=0;
virtual IParameterInfo* GetParameter(vint index)=0;
virtual ITypeInfo* GetReturn()=0;
virtual bool IsStatic()=0;
virtual void CheckArguments(collections::Array&
virtual Value Invoke(const Value thisObject, collections::Array&
virtual Value CreateFunctionProxy(const Value thisObject) = 0;
};
展開前(這部分是你可以選擇要不要鏈接的。我曾經考慮過這部分代碼也用代碼生成器來生成,最後發現實現不了我的需求,因此人肉寫):
BEGIN_INTERFACE_MEMBER_NOPROXY(IMethodInfo)
CLASS_MEMBER_BASE(IMemberInfo)
CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerMethodGroup)
CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerProperty)
CLASS_MEMBER_PROPERTY_READONLY_FAST(ParameterCount)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Return)
CLASS_MEMBER_METHOD(GetParameter, { L"index" })
CLASS_MEMBER_METHOD(IsStatic, NO_PARAMETER)
CLASS_MEMBER_METHOD(CheckArguments, { L"arguments" })
CLASS_MEMBER_METHOD(Invoke, { L"thisObject" _ L"arguments" })
CLASS_MEMBER_BASE(IMemberInfo)
END_INTERFACE_MEMBER(IMethodInfo)
展開後(從下面開始都是編譯的過程):
template&<&> struct CustomTypeDescriptorSelector&
AddBaseType(description::GetTypeDescriptor&
{ const wchar_t* parameterNames[]={L""}; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType&
{ const wchar_t* parameterNames[]={L""}; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType&
{ const wchar_t* parameterNames[]={L""}; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType&
{ const wchar_t* parameterNames[]={L""}; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType&
{ const wchar_t* parameterNames[]={ L"index" }; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType& 展開後的這個類干一個非常簡單的事情。這是一個ITypeDescriptor的實現,在他的初始化函數裡面,會往自己身上把IMethodInfo的所有屬性和函數都一個一個添加到自己的元數據的數據結構裡面去。其中每一個函數當然都必須要能夠真的調用C++的函數。 取函數類型很簡單,娶一個指針然後去做模式匹配: LambdaRetriveType& 有了函數類型之後,就可以用這個類型構造一個寫好的IMethodInfo的實現,用來當作AddMethod的參數: Value InvokeInternal(const Value thisObject, collections::Array& Value CreateFunctionProxyInternal(const Value thisObject)override 最後就是那個InvokeInternal的函數了。IMethodInfo::Invoke把所有的參數都打包在了一個數組裡面,然後用variadic template argument做一個遞歸當循環,依次把數組裡面的內容一個一個反序列化(主要是把類型cast出來,並不是去解析字元串)出來,然後排好隊,調用函數。 template& 反射就是這麼做出來的,一套宏下來,一個ITypeDescriptor也做好了,就像C#的Type類一樣。剩下的就是註冊一下,就可以完美反射了。 記得以前有個同事說過年會抽獎系統作弊讓自己得獎的方法,就是讓代碼自己把作弊的那段給刪了,很適合php這種(手動滑稽...確實很多內部系統都是用php寫的),執行後不留痕迹。代碼大概應該是這個流程:
{ const wchar_t* parameterNames[]={L""}; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType&
{ const wchar_t* parameterNames[]={ L"arguments" }; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType&
{ const wchar_t* parameterNames[]={ L"thisObject" , L"arguments" }; auto methodInfo = new CustomMethodInfoImpl&< ClassType, vl::function_lambda::LambdaRetriveType&
AddBaseType(description::GetTypeDescriptor&
if (GetBaseTypeDescriptorCount() == 0 TDFlags == TypeDescriptorFlags::Interface) AddBaseType(description::GetTypeDescriptor&
template&
struct LambdaRetriveType&
{
typedef Func&
typedef R(FunctionType)(TArgs...);
typedef R ResultType;
};
template&
class CustomMethodInfoImpl&
{
protected:
R(__thiscall TClass::* method)(TArgs...);
{
TClass* object=UnboxValue&
return internal_helper::BoxedMethodInvoker&
}
{
TClass* object=UnboxValue&
Func&
return BoxParameter&
}
public:
CustomMethodInfoImpl(const wchar_t* parameterNames[], R(__thiscall TClass::* _method)(TArgs...), const wchar_t* _invokeTemplate, const wchar_t* _closureTemplate)
:MethodInfoImpl_StaticCpp(0, TypeInfoRetriver&
,method(_method)
{
internal_helper::ConstructorArgumentAdder&
}
};
template&
struct BoxedMethodInvoker
{
static Value Invoke(TClass* object, R(__thiscall TClass::* method)(TArgs...), MethodInfoImpl* methodInfo, collections::Array&
{
UnboxSpecifiedParameter(methodInfo, arguments, 0, args...);
R result = (object-&>*method)(args...);
return BoxParameter&
}
};
struct BoxedMethodInvoker&
{
static Value Invoke(TClass* object, void(__thiscall TClass::* method)(TArgs...), MethodInfoImpl* methodInfo, collections::Array&
{
UnboxSpecifiedParameter(methodInfo, arguments, 0, args...);
(object-&>*method)(args...);
return Value();
}
};
這段代碼運行後,從作弊開始到作弊結束的代碼就沒有了,但是抽獎的結果就有了233號。但如果代碼上線流程很規範的話,或者根本就沒有線上代碼的修改許可權,就不太好操作了。 算不上炫技,但是思路確實挺好的,2333333&
抬手一個template&class T&>
一年前隨手寫的,當時寫了倆語言版本,一個是Scheme版,一個是Python版。且看且隨意。
Lisp版:
Python版:
但我不知道咋定義「炫技」呀?我只能說我這個是「眼花繚亂」,應該別當成「炫技」的。請了解,謝謝~
宏吧。
compile_assert,編譯時期斷言,失敗會編譯錯誤,原理是利用sizeof x[-1]會編譯錯誤,1-2p,p=0,為1,p=1,為-1,sizeof x[1-2p],當p等於1時編譯出錯。
do {} while{0},循環中間的代碼,利用現在編譯器的優化功能,有時候會優化掉,相當於空語句。比如compile_assert就可以放到這裡。錯誤的時候編譯出錯,正確的時候沒有任何額外代碼產生。很多宏都會用到這個循環。
利用段功能跟宏,可以把一個結構數據存到特殊段裡面,利用段其實地址跟結束地址,就可以取得這個結構數組。使用宏的時候自動加入這個數據段,免去內存維護了,而且用到多少就多少。而且還能減少耦合。比如服務註冊,有n個服務可以編譯,每個服務有個函數入口,服務名稱。但服務不一定相同,有的服務在某些情況下不編譯,比如有的服務只在Windows有效。利用這個功能,就可以不用人工去管理這些服務了,服務管理器只需要看下那個特定段,就可以發現所有編譯進去的服務。而且調用服務的時候是通過函數指針的,不需要知道函數名。服務管理器代碼不需要include每個服務的頭文件。
下面舉個初始化的例子,模塊加入系統中需要初始化,利用上面這個功能,自動註冊初始化函數:
#ifdef CONFIG_LTO
/* Work around a LTO gcc problem: when there is no reference to a variable
* in a module it will be moved to the end of the program. This causes
* reordering of initcalls which the kernel does not like.
* Add a dummy reference function to avoid this. The function is
* deleted by the linker.
*/
#define LTO_REFERENCE_INITCALL(x)
; /* yes this is needed */
static __used __exit void *reference_##x(void)
{
return x;
}
#else
#define LTO_REFERENCE_INITCALL(x)
#endif
#define __define_initcall(fn, id)
static initcall_t __initcall_##fn##id __used
__attribute__((__section__(".initcall" #id ".init"))) = fn;
LTO_REFERENCE_INITCALL(__initcall_##fn##id)
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
...
可以定義多個初始化階段
//module.c
static int init_module_call(bool isbp)
{
...
}
pure_initcall(init_module_call);
上面申明一個static函數,然後註冊初始化函數。由於是static,0耦合,其他模塊不需要引用這個模塊的任何數據跟函數,只需要編譯進去就行,就會在initcall0這個數據段裡面註冊一個結構,而主函數只需要讀取這個段即可完成初始化,不需要知道每個模塊的初始化函數名。
extern initcall_t __initcallap_start[];
extern initcall_t __initcallap_end[];
extern initcall_t __initcall_start[];
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];
static initcall_t *initcall_levels[] __initdata = {
__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,
__initcall_end,
};
int __init do_one_initcall(initcall_t fn, bool isbp)
{
int ret;
if (initcall_debug)
ret = do_one_initcall_debug(fn, isbp);
else
ret = fn(isbp);
return ret;
}
static void __init do_initcall_level(int level, bool isbp)
{
initcall_t *fn;
for (fn = initcall_levels[level]; fn &< initcall_levels[level + 1]; fn++) do_one_initcall(*fn, isbp); }
ld文件:
.init.data : AT(ADDR(.init.data)) {
*(.init.data)
__initcall_start = .; *(.initcallearly.init)
__initcall0_start = .; *(.initcall0.init) *(.initcall0s.init)
__initcall1_start = .; *(.initcall1.init) *(.initcall1s.init)
__initcall2_start = .; *(.initcall2.init) *(.initcall2s.init)
__initcall3_start = .; *(.initcall3.init) *(.initcall3s.init)
__initcall4_start = .; *(.initcall4.init) *(.initcall4s.init)
__initcall5_start = .; *(.initcall5.init) *(.initcall5s.init)
__initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init)
__initcall6_start = .; *(.initcall6.init) *(.initcall6s.init)
__initcall7_start = .; *(.initcall7.init) *(.initcall7s.init)
__initcall_end = .;
}
在黑星際2的時候,為了過調用者檢測寫過一段我認為自己寫過最喪心病狂的代碼:模板彙編
星際2的上萬個函數中都有調用者檢測,也就是檢查堆棧里的調用者是否屬於遊戲模塊,如果不屬於則偷偷上報。如果作弊器主動調用遊戲函數,結果就會被檢測。
這裡簡單介紹一下Return-oriented programming (ROP) 技術。當一段程序執行到ret,就會跳轉到棧頂指向的地址。如果攻擊者可以入侵調用棧,通過小心地選擇壓棧的內容,使得每個額外的跳轉都指向 (某個想要執行的指令 + ret),就可以在宿主中執行任意程序。
如果要繞過一個函數的檢查,可以手動寫一段彙編找個trampoline,但假如需要繞過幾千個簽名各不同的函數難道也要手動寫嗎?有請萬能的C++出場—— (以下只拿x86的cdecl情況做例子,其他calling convention和x64有其他變化)
// ============================================================================================== //
// Bypass caller check varargs (cdecl) wrapper //
// ============================================================================================== //
template&
constexpr std::size_t SizeOfPack()
{
return sizeof(T);
}
template&
constexpr std::size_t SizeOfPack()
{
return sizeof(T) + SizeOfPack&();
}
template&
struct VarargsCallWrapperHelper
{
static const std::size_t kArgsSize = SizeOfPack&
static void* func;
static const void* kReturnHelperInstruction;
static void* MyPlaceAddr;
static void** JmpTarget;
static RetT __cdecl Jumper(ArgsT... args, ...) noexcept;
template&
static RetT Call(ArgsT... args, VarArgsT... va) noexcept
{
RetT result;
auto argsSize = kArgsSize/*variadic*/ + SizeOfPack&
auto backupJmpTarget = *JmpTarget;
__asm mov eax, myplace;
__asm mov[MyPlaceAddr], eax;
*JmpTarget = MyPlaceAddr;
Jumper(args..., va...);
myplace:
__asm add esp, [argsSize];
__asm mov[result], eax;
*JmpTarget = backupJmpTarget;
return result;
}
RESTORE_ALL_CODE_ANALYSIS_WARNINGS
};
template&
void * VarargsCallWrapperHelper&
template&
void * VarargsCallWrapperHelper&
template&
void** VarargsCallWrapperHelper&
template&
const void * VarargsCallWrapperHelper&
/* Stack when entering function
--------------------------
| game fake instruction | ESP+0h must be instruction within game code segment
--------------------------
| vararg call stack N |
--------------------------
| vararg call stack N - 1|
--------------------------
| ... |
--------------------------
| vararg call stack 1 |
--------------------------
*/
template&
RetT _declspec(naked) __stdcall VarargsCallWrapperHelper&
{
__asm
{
add esp, 4;
push kReturnHelperInstruction;
push func; //jump
retn;
}
}
//Call wrapper function 原理簡單說就是在調用時,向堆棧壓入某個遊戲模塊內的地址,而這個地址指向一個跳轉指令,例如JMP [0x????????] ,修改這個跳轉的目標讓它跳回原調用者。最大的問題在於cdecl可以不定參數長度,由調用者清棧,如何為傳給目標函數的參數清棧就成了問題。於是這裡利用了一個stdcall 函數負責傳參,主動替換掉返迴路徑到trampoline,再從trampoline到原函數的一個標籤。 貼個當時一個功能效果,拖拽滑鼠完美力場: http://v.youku.com/v_show/id_XNzk4MTc3NjMy.html?sharefrom=iphone
template&
RetT VarargsCallWrapper(void* funcAddr, ArgsT.../*copy intended*/ args, VarArgsT... va)
{
using WrapperT = VarargsCallWrapperHelper&
WrapperT::func = funcAddr;
return WrapperT::Call(std::move(args)..., va...);
}
在 .c 文件里,用include和main開個頭,配上各種小括弧和大括弧。
然後是#asm{ };//在C文件里嵌入彙編指令的意思。
把所有的程序都寫在上述的大括弧中。也就是在C語言里完全嵌入彙編指令,所有程序都是彙編。
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}{-# LANGUAGE RankNTypes #-}{-# LANGUAGE TypeFamilies #-}{-# LANGUAGE TypeOperators #-}{-# LANGUAGE KindSignatures #-}{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeApplications #-}{-# LANGUAGE ScopedTypeVariables #-}{-# LANGUAGE AllowAmbiguousTypes #-}{-# LANGUAGE Trustworthy #-}type family Min :: Nat -&> Nat -&> Nat where
type family Max :: Nat -&> Nat -&> Nat wheretype family Div :: Nat -&> Nat -&> Nat wheretype family Mod :: Nat -&> Nat -&> Nat wheretype family Gcd :: Nat -&> Nat -&> Nat wheretype family Lcm :: Nat -&> Nat -&> Nat where
type Divides n m = n ~ Gcd n m
newtype Magic n = Magic (KnownNat n =&> Dict (KnownNat n))
magic :: forall n m o. (Integer -&> Integer -&> Integer) -&> (KnownNat n, KnownNat m) :- KnownNat o
magic f = Sub $ unsafeCoerce (Magic Dict) (natVal (Proxy :: Proxy n) `f` natVal (Proxy :: Proxy m))axiom :: forall a b. Dict (a ~ b)
axiom = unsafeCoerce (Dict :: Dict (a ~ a))然後這時候,可以說, unsafeCoerce 的事,能叫作弊嗎
euclideanNat :: (1 &<= c) :- (a ~ (c * Div a c + Mod a c))
euclideanNat = Sub axiomplusCommutes :: forall n m. Dict ((m + n) ~ (n + m))
plusCommutes = axiomtimesCommutes :: forall n m. Dict ((m * n) ~ (n * m))
timesCommutes = axiomminCommutes :: forall n m. Dict (Min m n ~ Min n m)
minCommutes = axiommaxCommutes :: forall n m. Dict (Min m n ~ Min n m)
maxCommutes = axiomplusAssociates :: forall n m o. Dict (((m + n) + o) ~ (m + (n + o)))
plusAssociates = axiomtimesAssociates :: forall n m o. Dict (((m * n) * o) ~ (m * (n * o)))
timesAssociates = axiomminAssociates :: forall n m o. Dict (Min (Min m n) o ~ Min m (Min n o))
minAssociates = axiommaxAssociates :: forall n m o. Dict (Max (Max m n) o ~ Max m (Max n o))
maxAssociates = axiomgcdAssociates :: forall a b c. Dict (Gcd (Gcd a b) c ~ Gcd a (Gcd b c))
gcdAssociates = axiomlcmAssociates :: forall a b c. Dict (Lcm (Lcm a b) c ~ Lcm a (Lcm b c))
lcmAssociates = axiomminIsIdempotent :: forall n. Dict (Min n n ~ n)
minIsIdempotent = axiom摘自 Data.Constraint# 輸出CovScript內建的所有類型名# 注意其實CovScript的語句以換行符結束# 但為了方便引入了@begin和@end預處理指令支持跨行語句struct fooendvar sql=sqlite.open(":memory:")@beginvar types={ type(context), type(0), type(true), type(null), type(" "), type(""), type(new list), type({}), type(0:0), type({0:0}), type(number), type(system), type(type), type(new foo), type(runtime.exception("")), type(http://system.in), type(system.out), type({}.begin()), type((new list).begin()), type(iostream.seekdir.start), type(iostream.openmode.app), type(context.build("x")), type(darwin.red), type(darwin.pixel(" ",darwin.white,darwin.white)), type(darwin.get_drawable()), type(sql), type(sqlite.integer), type(sql.prepare("create table test(a integer)"))}@endfor it iterate types system.out.println(it)end
目前寫過最炫技的項目是CSAPP的datalab。。。
最炫技的代碼是datalab中的ilog2。。。
目標是用最少的legal ops(不計賦值符號=)實現對正數log2並取整的函數,常數只能用0x00~0xFF,類型只能用int/unsigned,不能用for、while、if等控制語句或其他函數。
只用了19個ops~
/*
* ilog2 - return floor(log base 2 of x), where x &> 0
* Example: ilog2(16) = 4
* Legal ops: ! ~ ^ | + &<&< &>&>
* Max ops: 90
* Rating: 4
*/
int ilog2(int x) {
int ans = (!(x &>&> 16)) &<&< 4;
ans ^= (!(x &<&< ans &>&> 24)) &<&< 3;
ans ^= 28;
ans ^= (!(x &>&> ans)) &<&< 2;
x = x &>&> ans;
ans ^= ((~0x5B) &>&> (x 30)) 3;
return ans;
}
貼個完整的當時的datalab的代碼:https://github.com/Seterplus/CSAPP/blob/master/datalab/bits.c
char add_1_byasm(char data) {
/*
pcode:
mov_reg_ptr eax,ptr_buffer 65, 03, 00, xx, xx, xx, xx
runasm ptr_data,3 99, xx, xx, xx, xx, 03, 00, 00, 00
mov_ptr_reg ptr_buffer,eax 65, 04, xx, xx, xx, xx, 00
*/
BYTE pcode_l[] = {
0x65, 0x03, 0x00,/*here*/0x00, 0x00, 0x00, 0x00,// 7
0x99,/*here*/0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,// 9
0x65, 0x04,/*here*/0x00, 0x00, 0x00, 0x00, 0x00,
0x00
};
UCHAR ASMCode[] = { 0x83,0xC0,0x01 };
/*
x86 asm
add eax, 1
*/
VMACHINE VM;
int t = 0;
t = data;
int * ptr_data = t;
void * ptr_asmcode = ASMCode;
memcpy(pcode_l[3], ptr_data, 4);
memcpy(pcode_l[8], ptr_asmcode, 4);
memcpy(pcode_l[18], ptr_data, 4);
VM_Init(VM);
VM_Run(VM, pcode_l);
VM_Destroy(VM);
return (char)t;
}
當然是一個可以一邊模擬一邊隨便和真實環境切換的VM了
1 倒立寫代碼。難度係數:5。注意事項:換手的時候小心摔倒。小心臉卡鍵盤。2 用腳寫代碼。難度係數:4。注意事項:不要寫出有味道的代碼。3 不開顯示器寫代碼。難度係數:8。注意事項:很多。首先要記住滑鼠一開機是在屏幕正中間…4 和女朋友邊聊天邊寫代碼。難度係數:不確定。注意事項:只負責說「嗯」和」然後呢」的難度係數為1,女朋友特別能聊的難度係數為3,找不到女朋友的難度係數為10。5 邊玩遊戲邊寫代碼。難度係數:2。注意事項:不怕罵就行。單機不算。6 邊開車邊寫代碼。難度係數:9注意事項:《中華人民共和國道路交通安全法》《刑法》《民法通則》《中華人民共和國安全生產法》《治安管理處罰條例》等7 從後往前寫代碼。難度係數:7注意事項:先試試倒著背幾首詩,習慣倒背如流。8 二進位形式寫代碼。難度係數:3注意事項:一開始也許很慢,漸漸的你就習慣了。9 邊啪啪啪邊寫代碼。難度係數:10注意事項:別問我,不知道。
a=a^b;
b=a^b;a=a^b;當年大一時驚呆一眾小夥伴
正在我準備解釋一波然後深藏功與名時我們老師過來看了一眼說你以後工作上敢這麼寫會被打死的_Static_assert/static_assert 之前的變通方式、宏中使用 {} 的標準手法,都沒什麼炫技成分吧…
說到宏的話還有這個:
https://www.zhihu.com/question/57089104/answer/151906183在壓縮代碼的同時做到更易於維護。http://en.cppreference.com/w/cpp/algorithm/reverse還有這裡實現里的壓行操作也是比較炫技的。個人建議不要用,除非有非壓行不可的理由。預覽地址:
這就是預覽地址:方正的React實驗室(手機上看也可以,就是字體比較小)
這是項目地址:方正github「無恥求:星,沒星點贊,哈哈哈」
以前寫C++的時候沒能寫過啥絢麗技巧,後面學前端的時候倒是寫了不少。
80+代碼實現一個React版本的酷炫動效簡歷,之前寫的一個,這種炫技方式不難又簡單...
不是c++也來湊個熱鬧啦..
我們來實現下斷言,但是標準C不輸出函數名(不影響),為了炫(裝)技(逼),我們當然要加上啦!不得不說宏定義實在是太牛啦~
// assert.h
void _Assert(const char *info, const char *func, int line);#define assert(x) if(!(x)) _Assert("斷言失敗!文件:" __FILE__ ",函數:%s,行:%d--"" #x "".", __FUNCTION__, __LINE__)// _Assert.cvoid _Assert(const char *info, const char *func, int line){ fprintf(stderr, info, func, line); abort();}@mika
#define mian main有一天,
我照常打開供職公司豈安科技的官方主頁,
手癢右鍵查看『網頁源代碼』,
看到了如下產物:
真身在這裡
我們的程序猿GG和程序猿小姐姐,也是悄咪咪羞澀萌的(筆芯)
推薦閱讀:
※如何寫優美的c++代碼?
※為什麼C/C++相同內存布局的struct不能互相cast?
※程序員應該將精力放在研究編程語言本身還是用編程語言創造好的軟體?
※Google對C++的影響有多大?
※為什麼 C 語言源程序最後一行要是一個空行?