C प्रोग्रामिंग भाषा क्विज़
(stefansf.de)- C भाषा के नियम pointer comparison, aliasing, null pointer, और uninitialized values जैसी दिखने में सरल code को भी undefined behavior बना सकते हैं
- integer constants,
sizeof, character constants, औरuint8_tarithmetic में type selection और integer promotion की वजह से platform, notation, और intermediate assignment की स्थिति के अनुसार नतीजे बदल सकते हैं - function declarations में
foo()औरfoo(void), prototype का न होना, default argument promotions, और बिना return value वाले functions की C और C++ में वैधता या behavior अलग हो सकता है - array, pointer नहीं है; array parameters को pointer में adjust किया जाता है, और
a,&a,&a[0]का address एक ही दिखे तब भी type अलग होने की वजह से इन्हें एक-दूसरे के स्थान पर इस्तेमाल नहीं किया जा सकता - operator precedence और evaluation order अलग चीजें हैं, और
switchbody की संरचना से लेकर temporary object की lifetime तक, standard की wording वास्तविक execution result को प्रभावित करती है
undefined behavior और pointer नियम
-
pointer comparison और strict aliasing नियम
- एक ही type के pointers
pऔरqअगर एक ही address को point करें, तब भी यदि वे अलग objects से निकले हों और किसी एक ही aggregate या union object के हिस्से न हों, तोp == qcomparison undefined behavior हो सकता है - pointer सिर्फ संख्यात्मक address से अधिक abstract चीज है; यह बात संबंधित लेख में आगे समझाई गई है
intobject कोshortlvalue के रूप में access करने पर strict aliasing नियम के अनुसार undefined behavior होता हैunsigned charpointer अपवाद के रूप में किसी भी object को alias कर सकता है, इसलिएintobject कोunsigned charlvalue से access करना वैध हैunsigned charके लिए यह गारंटी है कि उसमें padding bits और trap representation नहीं होते, और C11 सेsigned charके लिए भी padding bits न होने की गारंटी है- type-based alias analysis पर संबंधित लेख में चर्चा की गई है
- एक ही type के pointers
-
null pointer और pointer representation
- null pointer का bit representation जरूरी नहीं कि सभी bits 0 ही हो
- C standard null pointer constant को परिभाषित करता है, लेकिन runtime पर null pointer representation या सामान्य pointer representation को परिभाषित नहीं करता
- Symbolics Lisp Machine 3600 संख्यात्मक pointer की जगह
<array-object, index>रूप का tuple इस्तेमाल करती है, और इसका null pointer representation<nil, 0>है - अतिरिक्त उदाहरण clc FAQ 5.17 में हैं
- constant
0context के अनुसार integer या null pointer बन सकता है, और(void *)0null pointer के रूप में evaluate होता है - सिर्फ इस वजह से कि expression
eका मान0है, यह गारंटी नहीं होती कि(void *)enull pointer होगा - केवल null pointer constant को pointer type में convert करने पर ही उसके null pointer के बराबर होने की गारंटी है
- null pointer पर arithmetic undefined behavior है, इसलिए
enull pointer हो तब भीe + 0के null pointer होने की गारंटी नहीं है
-
uninitialized values
- automatic storage duration वाले uninitialized object को पढ़ते समय, अगर वह object
registerstorage class का हो सकता है और उसका address कभी लिया न गया हो, तो C11 § 6.3.2.1 ¶ 2 के अनुसार यह undefined behavior है - यह नियम DR338 में चर्चित Intel Itanium architecture से जुड़ा है
- Itanium के सामान्य integer registers में 64 bits और एक trap bit होता है; यह trap bit
NaT(not-a-thing) बताता है कि register initialized है या नहीं - variable का address लेने पर यह शर्त हट जाती है, लेकिन value फिर भी indeterminate रहती है और वह trap representation या unspecified value हो सकती है
- trap representation को पढ़ना C11 § 6.2.6.1 ¶ 5 के अनुसार undefined behavior है
- यदि value unspecified हो, तो
x != xका परिणामtrueयाfalseदोनों हो सकता है, और अगरint xunspecified है, तोx *= 0के बाद भीxके 0 होने की गारंटी नहीं है - indeterminate और unspecified values पर DR260, DR451, N1793, N1818, N2012, N2013, N2221 में चर्चा की गई है
- automatic storage duration वाले uninitialized object को पढ़ते समय, अगर वह object
-
unsigned charऔरmemcpyunsigned chartype में C11 § 6.2.6.1 ¶ 3 के अनुसार trap representation नहीं होता, इसलिए इसकी initial value unspecified होती है- StackOverflow पर C committee member के उत्तर के अनुसार standard library function
memcpyको call करने के बादxकी value specified हो जानी चाहिए, और इस व्याख्या मेंx != xका परिणामfalseमाना जाता है - C standard में इसे समर्थन देने वाला आधार स्पष्ट नहीं है, और DR451 पर committee response कहता है कि indeterminate value पर library function का उपयोग undefined behavior है, जो इस व्याख्या से टकराता है
- यह प्रश्न अब भी खुला है, और आगे की चर्चा Uninitialized Reads में है
पूर्णांक constant, प्रमोशन, sizeof
-
पूर्णांक constant का निरूपण और type
- बिना suffix वाले दशमलव पूर्णांक constant हमेशा signed type की सूची में से चुने जाते हैं, लेकिन octal और hexadecimal constant signed या unsigned type हो सकते हैं
- C17 § 6.4.4.1 के अनुसार पूर्णांक constant का type उस सूची के पहले type से तय होता है जो उस मान को represent कर सके
- जब suffix न हो, तो दशमलव constant के लिए क्रम
int,long int,long long intहोता है, और octal/hexadecimal constant के लिए क्रमint,unsigned int,long int,unsigned long int,long long int,unsigned long long intहोता है INT_MAX+1सेUINT_MAXके बीच के constant का type इस बात पर बदल सकता है कि वह दशमलव है या hexadecimal, और इससे ABI-सेंसिटिव code, जैसे variadic function call, में फर्क पड़ सकता है- Arm 32-bit architecture ABI में
intऔरlong32-bit के रूप में एक register में pass होते हैं, जबकिlong long64-bit के रूप में दो register में pass होता है - जिन platform पर
int32-bit है, वहाँ-1 < 0x8000का परिणामtrueहोता है, और जिन platform परint16-bit है, वहाँfalse, जिससे portability problem हो सकती है - generic selection, C++ overloaded function, और
sizeof(0x80000000) == sizeof(2147483648)जैसे expression में भी constant type का अंतर परिणाम बदल सकता है
-
sizeof(int) > -1sizeofoperatorsize_ttype का unsigned integer लौटाता है- C11 § 6.3.1.8 की usual arithmetic conversions के अनुसार, अगर signed operand का rank unsigned operand से कम है, तो वह उसी rank के unsigned type में convert हो जाता है
-1के बराबर signed integer जब unsigned में convert होता है, तो वह उस rank का अधिकतम unsigned integer बन जाता है- इसलिए
sizeof(int) > -1का मूल्यांकन हमेशाfalseहोता है
-
character constant का type
- C में character constant, C11 § 6.4.4.4 ¶ 10 के अनुसार,
inttype का होता है - इसलिए
sizeof(char) == sizeof('x')हमेशाtrueहोगा, इसकी गारंटी नहीं है; सिर्फsizeof(int) == sizeof('x')की गारंटी है - integer character constant एक या अधिक multibyte character sequence हो सकता है, इसलिए
'abc'भी वैध है, और उसका representation implementation-defined है - एकल character वाले integer character constant का मान, उसी एकल character को दर्शाने वाले
chartype object के integer representation के बराबर होता है
- C में character constant, C11 § 6.4.4.4 ¶ 10 के अनुसार,
-
uint8_tarithmetic और division- भले ही
a,b,cको पढ़ने से पहले initialize किया गया हो, integer promotion और intermediate assignment की स्थिति के कारणxऔरzके मान अलग हो सकते हैं - हर variable value पहले
intआकार तक promote होती है, फिर addition और division किए जाते हैं, और हर assignment का परिणाम संबंधित variable type में truncate होकर store होता है - उदाहरण के लिए
a=255,b=1,c=2हो, तोxका मान((255 + 1) / 2) % 256 = 128होगा - intermediate variable
yका मान(255 + 1) % 256 = 0होगा, और उसके बादzका मान(0 / 2) % 256 = 0होगा, इसलिए128 != 0है - unsigned integer overflow defined behavior है
- modulo operation addition पर distributive होता है, इसलिए अगर division को addition से बदल दिया जाए, तो
xऔरzहमेशा समान होंगे - अगर पहली assignment को
uint8_t x = ((uint8_t)(a + b)) / c;में बदल दिया जाए, तब भीxऔरzहमेशा समान होंगे
- भले ही
-
constvariable और variable length arrayconstसे qualified variablesnऔरmको array size के रूप में इस्तेमाल करने पर भी, ये C में integer constant expression नहीं होते- C11 § 6.6 ¶ 6 में integer constant expression को integer constant, enumeration constant, character constant, ऐसा
sizeof,_Alignof, cast का तत्काल operand बनने वाला floating constant जिसका परिणाम integer constant हो, आदि तक सीमित किया गया है - यदि array size expression integer constant expression न हो, तो C11 § 6.7.6.2 ¶ 4 के अनुसार वह variable length array बन जाता है
- variable length array file scope में अनुमति प्राप्त नहीं है, इसलिए global array
xवाला compilation unit compile नहीं होगा - block scope में variable length array की अनुमति है, इसलिए local array
yवाला compilation unit compile हो सकता है - variable length array एक conditional feature है जिसे implementation support न भी करे, इसलिए जो compiler इसे support नहीं करते, उनमें block scope वाला उदाहरण भी compile नहीं हो सकता
- C++ में दोनों compilation unit compile हो जाते हैं, और C++ में variable length array की अवधारणा नहीं होने से
yको 42 elements वाले सामान्य array के रूप में compile किया जाता है
फ़ंक्शन घोषणा, रिटर्न वैल्यू, linkage
-
foo()औरfoo(void)foo()रूप की फ़ंक्शन घोषणा ऐसे फ़ंक्शन की घोषणा करती है जिसके arguments की संख्या और type अज्ञात हों, जबकिfoo(void)बिना arguments वाले nullary function की घोषणा करती है- यह अंतर फ़ंक्शन declaration·definition·prototype पर लेख में समझाया गया है
- argument सूची के बिना की गई घोषणा केवल फ़ंक्शन का नाम प्रस्तुत करती है और arguments की संख्या व type को परिभाषित नहीं करती, इसलिए बाद की फ़ंक्शन definition के साथ मिलकर वैध हो सकती है
- prototype के बिना फ़ंक्शन call होने पर default argument promotions लागू होते हैं और
float,doubleमें promote हो जाता है - promotion के बाद का फ़ंक्शन type यदि वास्तविक फ़ंक्शन definition के type के साथ compatible नहीं है, तो declaration और definition का संयोजन वैध नहीं होता
- declaration के बिना फ़ंक्शन call, C में implicit function की वजह से compile हो सकता है, लेकिन C++ में यह compile error है
- declaration के बिना
bar(42)जैसा call करने पर integer argument promotion लागू होता है और42,intके रूप में व्यक्त होता है, इसलिए यदिbarकिसी return typeTके लिएT (*)(int)के साथ compatible नहीं है, तो यह undefined behavior बनता है
-
value-returning फ़ंक्शन जो कोई मान return नहीं करता
- यदि किसी फ़ंक्शन का return type
intहै और वह कोई मान return नहीं करता, तब भी C में यह वैध हो सकता है, बशर्ते call के result value का उपयोग न किया जाए - K&R C में
voidtype नहीं था और type छोड़ देने पर default typeintमाना जाता था, इसलिए मान return न करने वाले फ़ंक्शन और implicitintनियम का ऐतिहासिक संबंध है - implicit
intनियम C99 में हटा दिया गया था, और संबंधित चर्चा N661 तथा C99 rationale में है - C17 § 6.9.1 ¶ 12 के अनुसार यदि execution फ़ंक्शन के अंत के
}तक पहुँच जाए और caller फ़ंक्शन call के मान का उपयोग करे, तो यह undefined behavior है - C++98 § 6.6.3 ¶ 2 में value-returning फ़ंक्शन के अंत तक बहकर पहुँचना स्वयं बिना मान वाले
returnके बराबर है, और value-returning फ़ंक्शन में यह undefined behavior बनता है - C++ compiler आम तौर पर यह सिद्ध नहीं कर सकते कि किसी branch में
abort_program()execution समाप्त करता है या नहीं, इसलिए ऐसे मामले में वे error की जगह केवल diagnostic दे सकते हैं
- यदि किसी फ़ंक्शन का return type
-
linkage और
extern- यदि पहले की declaration दिखाई देने वाले scope में उसी identifier को
externके साथ फिर से declare किया जाए, तो बाद की declaration का linkage, पहले वाली declaration के linkage के समान होगा - C17 § 6.2.2 ¶ 4 यह निर्धारित करता है कि यदि पहले की declaration ने internal या external linkage निर्दिष्ट किया था, तो बाद की
externdeclaration का भी वही linkage होगा - यदि पहले की declaration दिखाई नहीं देती, या पहले की declaration में linkage नहीं था, तो
externidentifier का external linkage होगा - उल्टे क्रम में declaration के संयोजन undefined behavior बन सकते हैं, और GCC व Clang इसे पकड़ लेते हैं
- यदि पहले की declaration दिखाई देने वाले scope में उसी identifier को
qualifiers और incomplete type
-
फ़ंक्शन parameters में
const- यदि फ़ंक्शन declaration में parameter
x,constसे qualified है लेकिन फ़ंक्शन definition में नहीं, और फ़ंक्शन body मेंxको मान लिखा जाता है, तब भी यह वैध है - C11 § 6.7.6.3 ¶ 15 के अनुसार फ़ंक्शन parameter type compatibility और composite type तय करते समय qualified type के रूप में घोषित प्रत्येक parameter को उसकी unqualified version के रूप में माना जाता है
- यही विषय DR040 में भी लिया गया है
- यदि फ़ंक्शन declaration में parameter
-
फ़ंक्शन return type में
const- यदि केवल फ़ंक्शन definition का return type
constसे qualified हो और declaration का नहीं, तो इसका उत्तर सिर्फ़ सही या ग़लत कहना आसान नहीं है - समग्र सहमति यह रही है कि rvalue के qualifiers को नज़रअंदाज़ किया जाना चाहिए, लेकिन C11 तक के standard text ने इसे स्पष्ट रूप से नहीं संभाला था
- C17 में यह स्पष्ट किया गया कि cast, lvalue conversion और function declarator में rvalue qualifiers को नज़रअंदाज़ किया जाना चाहिए
- C17 § 6.7.6.3 ¶ 5 में स्पष्ट रूप से कहा गया कि फ़ंक्शन द्वारा return किया गया type,
Tकी unqualified version होता है, और यह wording C17 में जोड़ी गई थी - return type के
constqualifier अलग होने पर भी फ़ंक्शन type assignment वैध हो सकता है - अतिरिक्त चर्चा DR423 और DR481 में है
- यदि केवल फ़ंक्शन definition का return type
-
incomplete struct और global variable
- global variable declaration के समय यदि
struct fooincomplete type है और उसका size ज्ञात नहीं है, तब भी यदि उसी translation unit में बाद में type complete हो जाता है, तो कुछ स्थितियों में यह अनुमति है - global variable या incomplete type array पर भी इसी तरह का logic लागू होता है
- यह विषय DR016 में भी चर्चा में है
- global variable declaration के समय यदि
-
voidtype का external object- internal linkage वाले
voidtype variable की declaration वैध नहीं है, लेकिन external linkage वालेvoidtype variable की declaration व्याकरण की दृष्टि से वैध है और C11 standard में कहीं भी इसे स्पष्ट रूप से निषिद्ध नहीं किया गया है - C11 § 6.2.5 ¶ 19 के अनुसार
voidtype, मानों के रिक्त समुच्चय से बना incomplete object type है जो complete नहीं हो सकता - C11 § 6.3.2.1 ¶ 1, lvalue को
voidके अलावा object type वाले expression के रूप में परिभाषित करता है, इसलिएvoidtype object नामfoo, वैध lvalue नहीं है - C11 के आधार पर external
voidobject पर कोई अर्थपूर्ण और conforming operation सोचना कठिन है - DR012 में बताया गया है कि यदि type को
const voidमें बदला जाए तो objectfooका address लेना वैध हो जाता है, जो जानबूझकर बनाई गई सुविधा से अधिक एक oversight जैसा लगता है
- internal linkage वाले
-
pointer-
constconversion- जब
Tderived object type है, तबcpassignment वैध है, लेकिनcppassignment वैध है या नहीं, इसका संक्षिप्त उत्तर नहीं है - यह विषय implicit pointer to const conversion पर लेख में लिया गया है
- जब
array, string literal, pointer adjustment
-
array, pointer नहीं है
- array initialization और pointer initialization समतुल्य नहीं हैं
- पहला रूप automatic या static storage duration वाले modifiable array को initialize करता है
- दूसरा रूप ऐसे pointer को initialize करता है जो static storage duration वाले array को point करता है, और वह array आवश्यक नहीं कि modifiable हो
- array, pointer नहीं है, और विवरण संबंधित लेख में है
-
a,&a,&a[0]int a[42];मेंa,&a, और&a[0], तीनों array के पहले element के address के रूप में evaluate होते हैं- लेकिन इन तीनों expressions के type अलग-अलग हैं, इसलिए इन्हें परस्पर बदलकर इस्तेमाल नहीं किया जा सकता
- विवरण संबंधित लेख में है
-
array parameters और local array
- यदि फ़ंक्शन parameter type “
Tका array” है, तो उसे “Tको point करने वाले pointer” में adjust किया जाता है - भले ही parameter
x,int[42]जैसा दिखे, वास्तव में उसेint *के रूप में माना जाता है - यदि local variable
y,int[42]है, तोsizeof(y),42 * sizeof(int)होता है - सामान्यतः object pointer का size, 42 integers के size के बराबर नहीं होता, इसलिए
sizeof(x) == sizeof(y)आम तौर परfalseहोता है - विवरण संबंधित लेख में है
- यदि फ़ंक्शन parameter type “
ऑपरेटर, evaluation order, control flow
-
x+++y- C में C++ की तरह नए ऑपरेटर define नहीं किए जा सकते, इसलिए
+++जैसा कोई नया ऑपरेटर नहीं है x+++yको मौजूदा ऑपरेटरों के संयोजन के रूप में समझा जाता है, और यह(x++) + yके बराबर है--*--pभी कोई नया ऑपरेटर नहीं, बल्कि मौजूदा ऑपरेटरों का संयोजन है--*--p--(*(--p))के बराबर है, और उदाहरण में इसका मान-1निकलता है तथा side effect के रूप मेंx[0]में-1assign होता है
- C में C++ की तरह नए ऑपरेटर define नहीं किए जा सकते, इसलिए
-
arithmetic operands का evaluation order
- ऑपरेटर precedence अच्छी तरह परिभाषित है, लेकिन arithmetic operands का evaluation order परिभाषित नहीं है
(x=1) + (x=2)में दोनों assignment किस क्रम में होंगे यह तय नहीं है, इसलिएxका अंतिम मान1होगा या2यह निश्चित नहीं है; इस वजह से यह undefined behavior है-std=c11 -O2विकल्प पर GCC 8.2.1 उदाहरण expression का मान4निकालता है, जबकि Clang 7.0.03निकालता है
-
logical operators का evaluation order
- logical operators
&&और||में operands का evaluation order भी स्पष्ट रूप से परिभाषित है - C standard की भाषा में, पहले operand के evaluation और दूसरे operand के evaluation के बीच एक sequence point मौजूद होता है
- उदाहरण में पहले
x=1evaluate होता है औरtrueबनता है, फिरx=2evaluate होता है और वह भीtrueबनता है, इसलिए पूरा expressiontrueहोता है
- logical operators
-
switchके body की मुक्त संरचनाswitchstatement का body कोई भी statement हो सकता है, इसलिए loop औरifके मिले-जुले ढांचे भी वैध हो सकते हैं- भले ही
ifstatement की control expression हमेशाfalseहो, उसके अंदर कीtruebranch मेंcaselabel हो तो वह statement live हो जाता है, औरprintf("1");dead code नहीं होता case 2पर jump करने पर loop का clause-1 और control expression execute नहीं भी हो सकते, इसलिए variableiको पहले से initialize किया हुआ होना चाहिएcase 1मेंbreakन होने से fall through हो जाए, तब भी अगरcase 1ifकीtruebranch में है औरcase 2falsebranch में, तो executioncase 2को छोड़करcase 3तक जारी रह सकता है- तीन calls
foo(0); foo(1); foo(2);के बाद console output02313223होगा - loop और switch को मिलाकर बना एक प्रसिद्ध वास्तविक उदाहरण Duff's device है
temporary object lifetime और C standard version के अंतर
- कुछ code fragments C11 में undefined behavior हैं, लेकिन C99 में ज़रूरी नहीं कि ऐसे हों
- C11 में कुछ objects की lifetime छोटी कर दी गई है, इसलिए function call से लौटने वाला object केवल तब तक जीवित रहता है जब तक right-hand side evaluate हो रहा हो
- C99 में वही object enclosing block के अंत तक जीवित रहता है
- lifetime समाप्त हो चुके object को reference करना C11 § 6.2.4 ¶ 2 के अनुसार undefined behavior है
- C99 में भी automatic storage duration वाले object की lifetime सबसे नज़दीकी enclosing block से बंधी होती है, इसलिए उस block के बाहर object को reference करना undefined behavior है
- C11 § 6.2.4 ¶ 8 यह निर्धारित करता है कि यदि struct या union type का non-lvalue expression किसी array member को शामिल करता है, तो वह automatic storage duration और temporary lifetime वाले object को refer करता है
- इस temporary object की lifetime expression के evaluate होने पर शुरू होती है, और जिस full expression या full declarator में वह शामिल है उसके evaluation के अंत में समाप्त हो जाती है
- temporary lifetime वाले object को modify करने की कोशिश undefined behavior है
- यह उदाहरण N1285 से लिया गया है, और अतिरिक्त चर्चा भी वहीं उपलब्ध है
1 टिप्पणियां
Lobste.rs की राय
प्रश्न 4 C23 में वैध नहीं है, लेकिन उससे पहले वैध था
प्रश्न 10 न सही उत्तर है न गलत, इसलिए उसे multiple-choice कहना थोड़ा खटकता है
प्रश्न 15 तकनीकी रूप से गलत था, खासकर प्रश्न 13 के संदर्भ में, और प्रश्न 20 "निर्दिष्ट नहीं" है, इसलिए वह भी किसी उत्तर में नहीं आता
प्रश्न 30 पढ़ने के तरीके पर निर्भर होने की वजह से अस्पष्ट है
फिर भी 31 में से 27 सही किए, और compiler developer होना शायद थोड़ा काम आया
लगभग चार सवाल हल करने के बाद, C इतना simple है कि side project में इस्तेमाल किया जा सकता है वाली जो थोड़ी-बहुत भावना बची थी, वह खत्म हो गई
clangमें-std=<language-standard>-pedantic -Wall -Wextraका इस्तेमाल करें और हर warning आने पर सच में उसे ठीक करें, और pointer casting व pointer manipulation को जितना हो सके टालें, तो शायद बड़े pitfalls से बचा जा सकता हैआजकल GCC/
clangwarnings काफ़ी अच्छी हैं, और <language-standard> के लिए c89, c99, c11, c23 इस्तेमाल किए जा सकते हैंअगर tcc जैसा compiler इस्तेमाल करें, जो अजीब optimizations नहीं करता, तो कम विचित्र surprises मिलेंगे
मैंने बस "यहाँ सबसे बेतुका behavior क्या होगा?" के आधार पर चुना और 32 में से 21 सही निकले
जो ज़्यादातर गलत हुए, वह इसलिए कि मैंने उस बेतुकेपन की गहराई तक पर्याप्त नहीं सोचा
C को 15 साल से भी पहले बस थोड़ा-सा छुआ था, और ऐसी quiz देखकर उसे फिर से आज़माने का मन नहीं करता
C23 के हिसाब से प्रश्न 4 का उत्तर वैध नहीं है
दिलचस्प बात यह है कि मैंने काफ़ी समय से C इस्तेमाल नहीं किया, फिर भी 32 में से 27 सही किए
ऐसी ही चीज़ों की वजह से मैं static checker और linter पर निर्भर रहा हूँ
प्रश्न 1 से ही अटपटा लगा
यह नहीं सोचा गया कि वे pointers कहाँ से आ सकते हैं, और वहाँ बताए गए मामले के सही होने के लिए बहुत विशेष शर्तें चाहिए
ज़्यादातर मामलों में उन pointers को बनाने की कोशिश करना ही undefined behavior है, लेकिन फिर भी इसे निष्पक्ष माना जा सकता है
प्रश्न 3 सच में चौंकाने वाला था, और C का एक और pitfall निकला
यह बात ही बहुत परेशान करने वाली है कि C integer literals के fixed types होते हैं
integer promotion के नियम कुछ हद तक चीज़ों को संभाल लेते हैं, लेकिन वही errors का स्रोत भी हैं
आधुनिक भाषाओं को ज़्यादातर, या सभी implicit numeric casting पर रोक लगानी चाहिए, और जहाँ संभव हो वहाँ context से literal type infer करना चाहिए, और जहाँ संभव न हो वहाँ explicit casting की मांग करनी चाहिए
प्रश्न 6 के बाद मैंने test पर भरोसा करना छोड़ दिया
शुरुआत में इसलिए, क्योंकि प्रश्न 5 का उत्तर मानो प्रश्न 6 को गलत करवाने के लिए ही बनाया गया था, लेकिन दोबारा देखने पर लगा कि प्रश्न 6 खुद ही गलत है
व्याख्या कहती है कि function call undefined behavior है, लेकिन सवाल यह था कि function definition वैध है या नहीं, और शायद उसके वैध होने की पूरी संभावना थी
और ऐसा बहुत दुर्लभ मामला भी नहीं लगता
switch()वाला सवाल सच में बहुत अच्छा थापेचीदा था, लेकिन उसे दिमाग़ में हल करने की प्रक्रिया बहुत मज़ेदार थी