मुझे पता है कि सभी सी संकलक कार्यान्वयन के पीछे एक मानक है, इसलिए कोई छिपी हुई विशेषताएं नहीं होनी चाहिए। इसके बावजूद, मुझे यकीन है कि सभी सी डेवलपर्स के पास छिपी / गुप्त चालें हैं जो वे हर समय उपयोग करते हैं।
मुझे पता है कि सभी सी संकलक कार्यान्वयन के पीछे एक मानक है, इसलिए कोई छिपी हुई विशेषताएं नहीं होनी चाहिए। इसके बावजूद, मुझे यकीन है कि सभी सी डेवलपर्स के पास छिपी / गुप्त चालें हैं जो वे हर समय उपयोग करते हैं।
जवाबों:
कार्य बिंदु। आप फंक्शन पॉइंटर्स टेबल का उपयोग लागू करने के लिए कर सकते हैं, उदाहरण के लिए, फास्ट इनडायरेक्ट-थ्रेडेड कोड इंटरप्रिटर्स (FORTH) या बाइट-कोड डिस्पैचर्स, या OO- जैसे वर्चुअल तरीकों का अनुकरण करने के लिए।
फिर मानक पुस्तकालय में छिपे हुए रत्न होते हैं, जैसे कि क्यूसोर्ट (), बीएसओआरसी (), स्ट्रैप्रबक (), स्ट्रैस्पन () [बाद के दो स्ट्रेटोक () प्रतिस्थापन को लागू करने के लिए उपयोगी होते हैं।
सी की एक मिसफिट यह है कि हस्ताक्षरित अंकगणित अतिप्रवाह अपरिभाषित व्यवहार (यूबी) है। इसलिए जब भी आप एक्स + वाई जैसे कोई अभिव्यक्ति देखते हैं, तो दोनों पर हस्ताक्षर किए जा रहे हैं, यह संभावित रूप से अतिप्रवाह और यूबी का कारण बन सकता है।
GCC संकलक की एक चाल के अधिक, लेकिन आप संकलक के लिए शाखा संकेत दे सकते हैं (लिनक्स केनन में आम)
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
देखें: http://kerneltrap.org/node/4705
इसके बारे में मुझे जो पसंद है वह यह है कि यह कुछ कार्यों के लिए कुछ अभिव्यक्तियाँ भी जोड़ता है।
void foo(int arg)
{
if (unlikely(arg == 0)) {
do_this();
return;
}
do_that();
...
}
int8_t
int16_t
int32_t
uint8_t
uint16_t
uint32_t
ये मानक में एक वैकल्पिक आइटम हैं, लेकिन यह एक छिपी हुई विशेषता होनी चाहिए, क्योंकि लोग लगातार उन्हें फिर से परिभाषित कर रहे हैं। एक कोड आधार जो मैंने काम किया है (और अभी भी करते हैं, अभी के लिए) में कई पुनर्मूल्यांकन हैं, सभी अलग-अलग पहचानकर्ताओं के साथ हैं। अधिकांश समय यह प्रीप्रोसेसर मैक्रोज़ के साथ होता है:
#define INT16 short
#define INT32 long
और इसी तरह। यह मुझे अपने बालों को बाहर निकालना चाहता है। बस मानक मानक पूर्णांक टाइपिंग का उपयोग करें!
अल्पविराम ऑपरेटर का व्यापक रूप से उपयोग नहीं किया जाता है। यह निश्चित रूप से दुरुपयोग किया जा सकता है, लेकिन यह बहुत उपयोगी भी हो सकता है। यह प्रयोग सबसे आम है:
for (int i=0; i<10; i++, doSomethingElse())
{
/* whatever */
}
लेकिन आप इस ऑपरेटर का उपयोग कहीं भी कर सकते हैं। का निरीक्षण करें:
int j = (printf("Assigning variable j\n"), getValueFromSomewhere());
प्रत्येक कथन का मूल्यांकन किया जाता है, लेकिन अभिव्यक्ति का मूल्य अंतिम कथन का मूल्यांकन किया जाएगा।
प्रारंभिक संरचना शून्य करने के लिए
struct mystruct a = {0};
यह सभी स्ट्रेक्चर तत्वों को शून्य कर देगा।
memset
/ calloc
do "all बाइट्स ज़ीरो" (अर्थात भौतिक शून्य), जो वास्तव में सभी प्रकारों के लिए परिभाषित नहीं है। उचित तार्किक शून्य मानों के साथ सब कुछ{ 0 }
सूचित करने की गारंटी है । उदाहरण के लिए, पॉइंटर्स अपने उचित अशक्त मूल्यों को प्राप्त करने के लिए गुरुंटेड हैं, भले ही दिए गए प्लेटफ़ॉर्म पर नल-मान हो । 0xBAADFOOD
memset
( 0
दूसरे तर्क के साथ) करता है। जब आप स्रोत कोड में ऑब्जेक्ट को इनिशियलाइज़ / असाइन (या ) करते हैं तो आपको लॉजिकल ज़ीरो मिलता है । ये दो प्रकार के शून्य आवश्यक रूप से एक ही परिणाम नहीं देते हैं। जैसा कि सूचक के साथ उदाहरण में। जब आप एक पॉइंटर पर करते हैं , तो आपको एक पॉइंटर मिलता है । लेकिन जब आप एक पॉइंटर को असाइन करते हैं , तो आपको अशक्त पॉइंटर मान मिलता है , जो भौतिक स्तर पर या कुछ और हो सकता है। 0
{ 0 }
memset
0x0000
0
0xBAADF00D
double
। आमतौर पर इसे IEEE-754 मानक के अनुसार लागू किया जाता है, जिसमें तार्किक शून्य और भौतिक शून्य समान होते हैं। लेकिन IEEE-754 को भाषा की आवश्यकता नहीं है। तो यह हो सकता है कि जब आप double d = 0;
(तार्किक शून्य) करते हैं, तो शारीरिक रूप से कब्जे वाली स्मृति में कुछ बिट d
शून्य नहीं होंगे।
बहु-चरित्र स्थिरांक:
int x = 'ABCD';
यह सेट x
करने के लिए 0x41424344
(या 0x44434241
, वास्तुकला के आधार पर)।
EDIT: यह तकनीक पोर्टेबल नहीं है, खासकर यदि आप int को क्रमबद्ध करते हैं। हालाँकि, यह सेल्फ-डॉक्यूमेंटिंग एनम बनाने के लिए बेहद उपयोगी हो सकता है। जैसे
enum state {
stopped = 'STOP',
running = 'RUN!',
waiting = 'WAIT',
};
यह बहुत आसान बना देता है यदि आप एक कच्ची मेमोरी डंप को देख रहे हैं और इसे देखने के लिए बिना किसी एनम का मान निर्धारित करने की आवश्यकता है।
मैंने कभी भी बिट फ़ील्ड का उपयोग नहीं किया, लेकिन वे अल्ट्रा-लो-लेवल सामान के लिए शांत लगते हैं।
struct cat {
unsigned int legs:3; // 3 bits for legs (0-4 fit in 3 bits)
unsigned int lives:4; // 4 bits for lives (0-9 fit in 4 bits)
// ...
};
cat make_cat()
{
cat kitty;
kitty.legs = 4;
kitty.lives = 9;
return kitty;
}
इसका मतलब है कि sizeof(cat)
जितना छोटा हो सकता है sizeof(char)
।
आरोन और लेपी द्वारा टिप्पणी को शामिल किया गया , धन्यवाद दोस्तों।
C का एक मानक है, लेकिन सभी C कंपाइलर पूरी तरह से कंप्लेंट नहीं हैं (मैंने अभी तक कोई कंप्लीट C99 कंपाइलर नहीं देखा है!)।
उन्होंने कहा, मेरे द्वारा पसंद की जाने वाली तरकीबें वे हैं जो प्लेटफार्मों के पार गैर-स्पष्ट और पोर्टेबल हैं क्योंकि वे सी सिमेंटिक पर भरोसा करते हैं। वे आम तौर पर मैक्रोज़ या बिट अंकगणित के बारे में हैं।
उदाहरण के लिए: एक अस्थायी चर का उपयोग किए बिना दो अहस्ताक्षरित पूर्णांक को स्वैप करना:
...
a ^= b ; b ^= a; a ^=b;
...
या "विस्तृत सी" जैसे परिमित राज्य मशीनों का प्रतिनिधित्व करने के लिए:
FSM {
STATE(x) {
...
NEXTSTATE(y);
}
STATE(y) {
...
if (x == 0)
NEXTSTATE(y);
else
NEXTSTATE(x);
}
}
निम्नलिखित मैक्रो के साथ प्राप्त किया जा सकता है:
#define FSM
#define STATE(x) s_##x :
#define NEXTSTATE(x) goto s_##x
सामान्य तौर पर, हालांकि, मुझे ऐसे ट्रिक्स पसंद नहीं हैं जो चालाक हैं लेकिन कोड को पढ़ने के लिए अनावश्यक रूप से जटिल बना दें (जैसा कि स्वैप उदाहरण) और मैं उन लोगों से प्यार करता हूं जो कोड को स्पष्ट करते हैं और सीधे इरादे को व्यक्त करते हैं (जैसे एफएसएम उदाहरण) ।
गूंथने के उपकरण जैसी इंटरलाकिंग संरचनाएं :
strncpy(to, from, count)
char *to, *from;
int count;
{
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
मैं नामित शुरुआती के बहुत शौकीन हूं, C99 में जोड़ा गया है (और लंबे समय तक जीसीसी में समर्थित है):
#define FOO 16
#define BAR 3
myStructType_t myStuff[] = {
[FOO] = { foo1, foo2, foo3 },
[BAR] = { bar1, bar2, bar3 },
...
सरणी आरंभीकरण अब निर्भर स्थिति नहीं है। यदि आप FOO या BAR के मान बदलते हैं, तो सरणी आरंभीकरण स्वचालित रूप से उनके नए मूल्य के अनुरूप होगा।
अनाम संरचनाएं और सरणियाँ मेरी पसंदीदा हैं। (cf. http://www.run.montefiore.ulg.ac.be/~martin/resources/kung-fg.html )
setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));
या
void myFunction(type* values) {
while(*values) x=*values++;
}
myFunction((type[]){val1,val2,val3,val4,0});
यह भी जुड़ा हुआ सूची instanciate करने के लिए इस्तेमाल किया जा सकता है ...
gcc में मेरे द्वारा आनंद ली जाने वाली C भाषा में कई एक्सटेंशन हैं, जो यहां मिल सकते हैं । मेरे पसंदीदा में से कुछ फ़ंक्शन विशेषताएँ हैं । एक अत्यंत उपयोगी उदाहरण स्वरूप विशेषता है। इसका उपयोग तब किया जा सकता है यदि आप एक कस्टम फ़ंक्शन को परिभाषित करते हैं जो प्रिंटफ प्रारूप स्ट्रिंग लेता है। यदि आप इस फ़ंक्शन विशेषता को सक्षम करते हैं, तो यह सुनिश्चित करने के लिए कि आपके प्रारूप स्ट्रिंग और तर्क मेल खाते हैं, gcc आपके तर्कों पर जाँच करेगा और उपयुक्त के रूप में चेतावनी या त्रुटियाँ उत्पन्न करेगा।
int my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
(छिपी हुई) विशेषता है कि जब मैंने पहली बार देखा तो मुझे "झटका" लगा था। यह सुविधा आपको स्वरूपण निर्दिष्ट करने के लिए चर का उपयोग करने की अनुमति देती है। कोड के लिए देखो, आप बेहतर देखेंगे:
#include <stdio.h>
int main() {
int a = 3;
float b = 6.412355;
printf("%.*f\n",a,b);
return 0;
}
* चरित्र इस प्रभाव को प्राप्त करता है।
खैर ... मुझे लगता है कि सी भाषा के मजबूत बिंदुओं में से एक इसकी पोर्टेबिलिटी और मानकता है, इसलिए जब भी मैं वर्तमान में उपयोग कर रहा हूँ में कुछ "छिपी हुई चाल" पाता हूं, मैं इसका उपयोग नहीं करने की कोशिश करता हूं क्योंकि मैं इसे रखने की कोशिश करता हूं मानक और संभव के रूप में पोर्टेबल के रूप में सी कोड।
संकलन-समय के दावे, जैसा कि पहले ही यहाँ चर्चा है ।
//--- size of static_assertion array is negative if condition is not met
#define STATIC_ASSERT(condition) \
typedef struct { \
char static_assertion[condition ? 1 : -1]; \
} static_assertion_t
//--- ensure structure fits in
STATIC_ASSERT(sizeof(mystruct_t) <= 4096);
लगातार स्ट्रिंग का संघनन
मैं जवाबों में पहले से ही इसे देखकर बहुत हैरान था, क्योंकि सभी संकलक मुझे इसके समर्थन के बारे में जानते हैं, लेकिन कई प्रोग्रामर इसे अनदेखा करते दिखते हैं। कभी-कभी यह वास्तव में आसान होता है और न केवल मैक्रोज़ लिखते समय।
मेरे वर्तमान कोड में केस का उपयोग करें: मेरे पास #define PATH "/some/path/"
एक कॉन्फ़िगरेशन फ़ाइल में है (वास्तव में यह मेकफाइल द्वारा तय किया गया है)। अब मैं फ़ाइलनाम सहित पूर्ण पथ का निर्माण करना चाहता हूं ताकि पुनर्मूल्यांकन खोला जा सके। यह बस जाता है:
fd = open(PATH "/file", flags);
के बजाय भयानक, लेकिन बहुत आम है:
char buffer[256];
snprintf(buffer, 256, "%s/file", PATH);
fd = open(buffer, flags);
ध्यान दें कि आम भयानक समाधान है:
खैर, मैंने कभी इसका इस्तेमाल नहीं किया है, और मुझे यकीन नहीं है कि क्या मैं कभी किसी को इसकी सलाह दूंगा, लेकिन मुझे लगता है कि यह प्रश्न साइमन तथम के सह-दिनचर्या चाल के उल्लेख के बिना अधूरा होगा ।
एरे या एम्स को इनिशियलाइज़ करते समय, आप इनिशियलाइज़र सूची में अंतिम आइटम के बाद अल्पविराम लगा सकते हैं। उदाहरण के लिए:
int x[] = { 1, 2, 3, };
enum foo { bar, baz, boom, };
ऐसा इसलिए किया गया ताकि यदि आप कोड स्वतः उत्पन्न कर रहे हैं तो आपको अंतिम अल्पविराम को समाप्त करने के बारे में चिंता करने की आवश्यकता नहीं है।
संरचना असाइनमेंट शांत है। बहुत से लोग महसूस नहीं करते हैं कि संरचनाएं भी मूल्य हैं, और उन्हें चारों ओर सौंपा जा सकता है, उपयोग करने की कोई आवश्यकता नहीं हैmemcpy()
, जब एक साधारण असाइनमेंट चाल करता है, तो ।
उदाहरण के लिए, कुछ काल्पनिक 2D ग्राफिक्स लाइब्रेरी पर विचार करें, यह एक (पूर्णांक) स्क्रीन समन्वय का प्रतिनिधित्व करने के लिए एक प्रकार को परिभाषित कर सकता है:
typedef struct {
int x;
int y;
} Point;
अब, आप ऐसी चीजें करते हैं जो "गलत" लग सकती हैं, जैसे कि एक फ़ंक्शन लिखें जो फ़ंक्शन तर्कों से प्रारंभिक बिंदु बनाता है, और इसे वापस लौटाता है, जैसे:
Point point_new(int x, int y)
{
Point p;
p.x = x;
p.y = y;
return p;
}
यह तब तक सुरक्षित है, जब तक कि वापसी (मूल्य) संरचना असाइनमेंट का उपयोग करके मूल्य द्वारा कॉपी की जाती है:
Point origin;
origin = point_new(0, 0);
इस तरह आप बिल्कुल साफ-सुथरी और ऑब्जेक्ट-ओरिएंटेड-ईश कोड लिख सकते हैं, सभी सादे मानक सी में।
अजीब वेक्टर अनुक्रमण:
int v[100]; int index = 10;
/* v[index] it's the same thing as index[v] */
सी कंपाइलर कई मानकों में से एक को लागू करते हैं। हालांकि, एक मानक होने का मतलब यह नहीं है कि भाषा के सभी पहलुओं को परिभाषित किया गया है। डफ का उपकरणउदाहरण के लिए, एक पसंदीदा 'छिपी हुई' विशेषता है जो इतनी लोकप्रिय हो गई है कि आधुनिक संकलक के पास यह सुनिश्चित करने के लिए विशेष प्रयोजन मान्यता कोड है कि अनुकूलन तकनीक इस अक्सर इस्तेमाल किए गए पैटर्न के वांछित प्रभाव को रोक नहीं पाती है।
सामान्य रूप से छिपी हुई सुविधाओं या भाषा की चालों को हतोत्साहित किया जाता है क्योंकि आप अपने कंपाइलर उपयोगों में से जो भी C मानक (रों) के रेजर किनारे पर चल रहे हैं। इस तरह के कई ट्रिक एक कंपाइलर से दूसरे में काम नहीं करते हैं, और अक्सर इस तरह के फीचर्स कंपाइलर सूट के एक वर्जन से दिए गए निर्माता के दूसरे वर्जन से फेल हो जाएंगे।
सी कोड को तोड़ने वाले विभिन्न ट्रिक में शामिल हैं:
जब भी प्रोग्रामर निष्पादन मॉडल के बारे में धारणाएँ बनाते हैं, तो अन्य समस्याएं और समस्याएं उत्पन्न होती हैं, जो सभी सी मानकों में 'कंपाइलर निर्भर' व्यवहार के रूप में निर्दिष्ट होती हैं।
Sscanf का उपयोग करते समय आप यह जानने के लिए% n का उपयोग कर सकते हैं कि आपको कहाँ पढ़ना जारी रखना चाहिए:
sscanf ( string, "%d%n", &number, &length );
string += length;
जाहिरा तौर पर, आप एक और उत्तर नहीं जोड़ सकते हैं, इसलिए मैं यहां एक दूसरे को शामिल करूंगा, आप "&&" और "" का उपयोग कर सकते हैं। सशर्त के रूप में:
#include <stdio.h>
#include <stdlib.h>
int main()
{
1 || puts("Hello\n");
0 || puts("Hi\n");
1 && puts("ROFL\n");
0 && puts("LOL\n");
exit( 0 );
}
यह कोड आउटपुट करेगा:
नमस्ते ROFL
कोड पर ब्रेक पॉइंट सेट करने के लिए INT (3) का उपयोग करना मेरा सर्वकालिक पसंदीदा है
सी की मेरी पसंदीदा "छिपी हुई" विशेषता, स्टैक पर वापस लिखने के लिए प्रिंट एन में% n का उपयोग है। आम तौर पर प्रिंटफ प्रारूप स्ट्रिंग के आधार पर स्टैक से पैरामीटर मानों को पॉप करता है, लेकिन% n उन्हें वापस लिख सकते हैं।
यहां 3.4.2 अनुभाग देखें । बहुत सारी कमजोरियों को जन्म दे सकता है।
संकलक का उपयोग करते हुए संकलन-समय धारणा-जाँच: स्थिर उदाहरण, लेकिन संकलन-समय विन्यास योग्य स्थिरांक के साथ पुस्तकालयों के लिए वास्तव में उपयोगी हो सकता है।
#define D 1
#define DD 2
enum CompileTimeCheck
{
MAKE_SURE_DD_IS_TWICE_D = 1/(2*(D) == (DD)),
MAKE_SURE_DD_IS_POW2 = 1/((((DD) - 1) & (DD)) == 0)
};
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
)
Gcc (c) में कुछ मजेदार फीचर्स हैं जिन्हें आप सक्षम कर सकते हैं, जैसे नेस्टेड फंक्शन डिक्लेरेशन, और a ?: b का फॉर्म ?: ऑपरेटर, जो अगर a है तो गलत नहीं है।
मुझे हाल ही में 0 बिटफिल्ड की खोज हुई।
struct {
int a:3;
int b:2;
int :0;
int c:4;
int d:3;
};
जो एक लेआउट देगा
000aaabb 0ccccddd
इसके बजाय: 0;
0000aaab bccccddd
0 चौड़ाई क्षेत्र बताता है कि अगले परमाणु इकाई पर निम्नलिखित बिटफिल्ड सेट किए जाने चाहिए ( char
)
C99- शैली चर तर्क मैक्रोज़, उर्फ
#define ERR(name, fmt, ...) fprintf(stderr, "ERROR " #name ": " fmt "\n", \
__VAR_ARGS__)
जिसका उपयोग किया जाएगा
ERR(errCantOpen, "File %s cannot be opened", filename);
यहां मैं स्ट्रिंगर ऑपरेटर और स्ट्रिंग निरंतर कॉन्सेटेशन का उपयोग करता हूं, अन्य विशेषताएं जो मुझे वास्तव में पसंद हैं।
कुछ मामलों में परिवर्तनीय आकार के स्वचालित चर भी उपयोगी होते हैं। इन्हें i nC99 जोड़ा गया और लंबे समय तक gcc में समर्थित किया गया।
void foo(uint32_t extraPadding) {
uint8_t commBuffer[sizeof(myProtocol_t) + extraPadding];
आप निश्चित आकार के प्रोटोकॉल शीर्षलेख और चर आकार डेटा के लिए कमरे के साथ स्टैक पर एक बफर के साथ समाप्त होते हैं। आप अल्लोका () के साथ समान प्रभाव प्राप्त कर सकते हैं, लेकिन यह सिंटैक्स अधिक कॉम्पैक्ट है।
आपको यह सुनिश्चित करना होगा कि इस रूटीन को कॉल करने से पहले एक्स्ट्रापैडिंग एक उचित मूल्य है, या आप स्टैक को उड़ाने का अंत करते हैं। आपको मॉलॉक या किसी अन्य मेमोरी आवंटन तकनीक को कॉल करने से पहले तर्कों की जांच करनी होगी, इसलिए यह वास्तव में असामान्य नहीं है।