आपकी पसंदीदा C प्रोग्रामिंग ट्रिक क्या है? [बन्द है]


134

उदाहरण के लिए, मैं हाल ही में इस linux कर्नेल में आया था:

/ * यदि स्थिति सत्य है तो संकलन त्रुटि / *
#define BUILD_BUG_ON (स्थिति) ((शून्य) साइज़ोफ़ (char [1 - 2 * !! !! (कंडीशन)]) !!

इसलिए, आपके कोड में, यदि आपके पास कुछ संरचना है, जो आकार में 8 बाइट्स की एक से अधिक होनी चाहिए, तो शायद कुछ हार्डवेयर बाधाओं के कारण, आप कर सकते हैं:

BUILD_BUG_ON ((आकार में ढांचा)% 8)! = 0);

और यह तब तक संकलित नहीं होगा जब तक कि संरचना रहस्य का आकार 8 का एक बहु नहीं है, और यदि यह 8 का गुणक है, तो कोई रनटाइम कोड उत्पन्न नहीं होता है।

एक और चाल मुझे पता है कि "ग्राफिक्स रत्न" पुस्तक से है जो एक ही हेडर फाइल को एक मॉड्यूल में घोषित करने और चर को शुरू करने की अनुमति देता है जबकि अन्य मॉड्यूल उस मॉड्यूल का उपयोग करते हैं, केवल उन्हें बाहरी घोषित करते हैं।

#ifdef DEFINE_MYHEADER_GLOBALS
# डेफिन ग्लोबल
#define INIT (x, y) (x) = (y)
#अन्य
# डिफाइन ग्लोबल एक्सटर्नल
#define INIT (x, y)
#अगर अंत

अंतर्राष्ट्रीय आईएनआईटी (एक्स, 0);
अंतर्राष्ट्रीय int somefunc (int a, int b);

इसके साथ, कोड जो x और somefunc को परिभाषित करता है:

#define DEFINE_MYHEADER_GLOBALS
# \ _ \ _ लोव_हैडर_फिल।

कोड है कि केवल एक्स और somefunc का उपयोग कर रहा है () करता है:

# \ _ \ _ लोव_हैडर_फिल।

तो आपको एक हेडर फ़ाइल मिलती है जो ग्लोबल्स के दोनों उदाहरणों की घोषणा करती है और प्रोटोटाइप की आवश्यकता होती है जहां वे आवश्यक हैं, और इसी एक्सक्लूसिव घोषणाएं।

तो, उन पंक्तियों के साथ आपके पसंदीदा सी प्रोग्रामिंग ट्रिक्स क्या हैं?


9
यह सी प्रीप्रोसेसर चाल की तरह अधिक लगता है।
jmucchiello

BUILD_BUG_ONमैक्रो के बारे में , #errorअंदर का उपयोग करने में क्या गलत है और #if?
रिकार्डो

जवाबों:


80

C99 अनाम सरणियों का उपयोग करके कुछ वास्तव में अच्छा सामान प्रदान करता है:

व्यर्थ चर को हटाना

{
    int yes=1;
    setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}

हो जाता है

setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));

विभिन्न प्रकार के तर्क पारित करना

void func(type* values) {
    while(*values) {
        x = *values++;
        /* do whatever with x */
    }
}

func((type[]){val1,val2,val3,val4,0});

स्टेटिक लिंक्ड लिस्ट

int main() {
    struct llist { int a; struct llist* next;};
    #define cons(x,y) (struct llist[]){{x,y}}
    struct llist *list=cons(1, cons(2, cons(3, cons(4, NULL))));
    struct llist *p = list;
    while(p != 0) {
        printf("%d\n", p->a);
        p = p->next;
    }
}

कोई भी मुझे यकीन है कि कई अन्य शांत तकनीकों के बारे में मैंने नहीं सोचा है।


2
मेरा मानना ​​है कि आपका पहला उदाहरण भी लिखा जा सकता है &(int){1}, यदि आप इसे थोड़ा और स्पष्ट करना चाहते हैं तो यहां आपका इरादा क्या है।
लिली बॉलर

67

क्वेक 2 सोर्स कोड पढ़ते हुए मैं कुछ इस तरह से आया:

double normals[][] = {
  #include "normals.txt"
};

(कम या ज्यादा, मेरे पास अब इसे जांचने के लिए कोड काम नहीं है)।

तब से, मेरी आँखों के सामने प्रीप्रोसेसर के रचनात्मक उपयोग की एक नई दुनिया खुल गई। मैं अब सिर्फ हेडर शामिल नहीं करता, लेकिन अब और फिर कोड का पूरा हिस्सा (यह पुन: प्रयोज्यता में सुधार करता है) :- पी

धन्यवाद जॉन कार्मैक! xD


13
आप क्विक सोर्स में तेज उलटा sqrt का उल्लेख किए बिना एक अनुकूलन थ्रेड में कारमैक नहीं कह सकते। en.wikipedia.org/wiki/Fast_inverse_square_root
pg1989

पहली जगह में उसे 0x5f3759df कहां से मिला?
RSH1

2
@ रोरी हार्वे: जब मैं इसे देख सकता था, तो यह पूरी तरह से अनुभवजन्य था। कुछ अध्ययन (मुझे याद नहीं है कि मैंने उन्हें कहाँ देखा था) यह प्रदर्शित किया कि यह इष्टतम के करीब था, लेकिन पूरी तरह से इष्टतम नहीं है। इसी तरह, ऐसा लगता है कि 64 बिट्स के लिए मूल्य की खोज की गई थी, कंप्यूटिंग के बजाय।
मथिउ एम।

50

मैं = {0};मेम को कॉल करने की आवश्यकता के बिना संरचनाओं को इनिशियलाइज़ करने के लिए उपयोग करने का शौकीन हूं।

struct something X = {0};

यह संरचना के सभी सदस्यों (या सरणी) को शून्य पर ले जाएगा (लेकिन किसी भी पेडिंग बाइट्स को नहीं - यदि आप के रूप में अच्छी तरह से शून्य करने की आवश्यकता है तो मेमसेट का उपयोग करें)।

लेकिन आपको पता होना चाहिए कि बड़े, गतिशील रूप से आवंटित संरचनाओं के लिए इसके साथ कुछ मुद्दे हैं ।


वैश्विक चर के लिए आवश्यक नहीं, वैसे।
स्ट्रैजर

5
स्थिर चर के लिए आवश्यक नहीं है । वैश्विक चर शून्य हो सकते हैं, लेकिन यह एक आवश्यकता नहीं है।
जेमी

4
मैं कभी-कभी इसका विस्तार करता हूं: const struct something zero_something = { 0 };और फिर मैं struct something X = zero_something;एक रूटीन या पार्ट- वे के साथ फ्लाई पर एक चर को रीसेट कर सकता हूं जो मैं 'X = zero_something;' का उपयोग कर सकता हूं। एकमात्र संभावित आपत्ति यह है कि इसमें कहीं से डेटा पढ़ना शामिल है; इन दिनों, एक 'मेमसेट ()' जल्दी हो सकता है - लेकिन मुझे असाइनमेंट की स्पष्टता पसंद है, और इनिशियलाइज़र में भी अन्य-से-शून्य मान का उपयोग करना संभव है (और) और () के बाद व्यक्तिगत सदस्य को ट्विस्ट के बाद एक साधारण कॉपी की तुलना में धीमी हो सकती है)।
जोनाथन लेफ़लर

45

अगर हम c ट्रिक्स के बारे में बात कर रहे हैं तो मेरे पसंदीदा को लूप के अनियंत्रित होने के लिए डफ का उपकरण होना चाहिए ! मैं वास्तव में गुस्से में इसका उपयोग करने के लिए मेरे साथ आने के सही अवसर की प्रतीक्षा कर रहा हूं ...


4
मैंने इसे एक बार एक प्रदर्शन योग्य लाभ प्राप्त करने के लिए उपयोग किया है, लेकिन इन दिनों यह बहुत सारे हार्डवेयर पर उपयोगी नहीं है। हमेशा प्रोफ़ाइल!
डैन ओल्सन

6
हाँ, उन लोगों की तरह जो संदर्भ को नहीं समझते हैं डफ का उपकरण बनाया गया था: "कोड पठनीयता" बेकार है यदि कोड काम करने के लिए पर्याप्त तेज़ नहीं है। संभवतः उन लोगों में से कोई भी नहीं है जिन्हें आपने कभी भी कठिन वास्तविक समय के लिए कोड करना पड़ा हो।
रॉब के

1
+1, मुझे वास्तव में कुछ समय के लिए डफ डिवाइस का उपयोग करने की आवश्यकता है। पहली बार एक लूप था जो मूल रूप से सिर्फ सामान की नकल करता था और रास्ते में कुछ छोटे परिवर्तन करता था। यह उस वास्तुकला में एक साधारण मेमची () की तुलना में बहुत तेज था।
मकिस

3
क्रोध आपके सहकर्मियों और उत्तराधिकारियों से होगा जिन्हें आपके बाद अपना कोड बनाए रखना है।
जोनाथन लेफ्लर

1
जैसा कि मैंने कहा, मैं अभी भी सही अवसर की प्रतीक्षा कर रहा हूं - लेकिन अभी तक किसी ने मुझे नाराज नहीं किया है। मैं अब लगभग 25 वर्षों से सी लिख रहा हूं, मुझे लगता है कि मैं पहली बार 90 के दशक की शुरुआत में डफ डिवाइस पर आया था और मुझे अभी तक इसका उपयोग नहीं करना पड़ा है। जैसा कि दूसरों ने टिप्पणी की है कि इस तरह की चाल कम और कम उपयोगी है क्योंकि कंपाइलर्स इस तरह के अनुकूलन पर बेहतर होते हैं।
जैक्सन

42

उपयोग __FILE__और __LINE__डिबगिंग के लिए

#define WHERE fprintf(stderr,"[LOG]%s:%d\n",__FILE__,__LINE__);

6
कुछ कंपाइलर्स पर आपको FUNCTION भी मिलता है ।
JBRWilkinson

11
__FUNCTION__के लिए सिर्फ एक उपनाम है __func__, और __func__c99 में है। काफी आसान है। __PRETTY_FUNCTION__सी में (जीसीसी) के लिए सिर्फ एक और उपनाम है __func__, लेकिन सी ++ में यह आपको पूर्ण फ़ंक्शन हस्ताक्षर देगा।
स्कलैंड

फ़ाइल फ़ाइल नाम का पूर्ण पथ दिखाता है इसलिए मैं बेसन ( फ़ाइल ) का उपयोग करता हूं
Jeegar Patel


28

एक बार मेरा एक साथी और मैंने एक मुश्किल ढेर भ्रष्टाचार बग को खोजने के लिए वापसी को फिर से परिभाषित किया।

कुछ इस तरह:

#define return DoSomeStackCheckStuff, return

4
उम्मीद है कि यह फ़ंक्शन बॉडी में # डिफाइंड था और आख़िर में # अविकसित था!
स्ट्रैजर

बहुत शौकीन नहीं है - पहली बात जो मेरे दिमाग में आती है वह यह है कि DoSomeStackCheckStuff कुछ बग की वजह से मेमोरी को खराब कर देता है और जो कोई भी कोड पढ़ रहा है उसे रिटर्न के पुनर्परिभाषित के बारे में पता नहीं है और आश्चर्य है कि / नरक क्या चल रहा है।
गिलिगन

8
@strager लेकिन यह मूल रूप से बेकार बना देगा। पूरे बिंदु को हर फ़ंक्शन कॉल में कुछ अनुरेखण जोड़ना है । अन्यथा आप केवल DoSomeStackCheckStuffउन कार्यों के लिए एक कॉल जोड़ेंगे जिन्हें आप ट्रेस करना चाहते थे।
क्लूलेस

1
@gilligan मुझे नहीं लगता कि यह उस प्रकार की चीज है जिसे आप हर समय सक्षम करते हैं; यह एक शॉट डिबगिंग कार्य के लिए बहुत आसान लगता है।
सूर्यास्त

क्या यह वास्तव में काम करता है? :) मैंने लिखा होगा #define return if((DoSomeStackCheckStuff) && 0) ; else return... मैं पागल के रूप में लगता है!
पाओलो बोन्जिनी

22

मुझे गतिशील आकार की वस्तु होने के लिए "स्ट्रक्चर हैक" पसंद है। यह साइट इसे बहुत अच्छी तरह से समझाती है (हालांकि वे C99 संस्करण को संदर्भित करते हैं जहां आप "str []" को एक संरचना के अंतिम सदस्य के रूप में लिख सकते हैं)। आप इस तरह एक स्ट्रिंग "ऑब्जेक्ट" बना सकते हैं:

struct X {
    int len;
    char str[1];
};

int n = strlen("hello world");
struct X *string = malloc(sizeof(struct X) + n);
strcpy(string->str, "hello world");
string->len = n;

यहाँ, हमने ढेर पर टाइप X की एक संरचना आवंटित की है जो एक int (len के लिए) का आकार है, साथ ही "hello world" की लंबाई, प्लस 1 (str 1 के बाद से) sizeof (X) में शामिल है)।

यह आम तौर पर तब उपयोगी होता है जब आप उसी ब्लॉक में कुछ वैरिएबल लंबाई डेटा से ठीक पहले "हेडर" रखना चाहते हैं।


मुझे व्यक्तिगत रूप से सिर्फ मॉलॉक () और रियललॉक () खुद को और जब भी मुझे लंबाई ढूंढने की आवश्यकता होती है तब स्ट्रलेन () का उपयोग करना आसान लगता है, लेकिन अगर आपको ऐसे प्रोग्राम की आवश्यकता है जो कभी भी स्ट्रिंग की लंबाई नहीं जानता है और संभवतः इसे खोजने की आवश्यकता होगी समय, यह शायद बेहतर सड़क है।
क्रिस लुत्ज़

4
"... C99 संस्करण जहां आप" str [] लिख सकते हैं "" मैंने शून्य संदर्भ में ऐसे संदर्भ में देखा है, जैसे str [0]; प्राय। मुझे लगता है कि यह C99 है। मुझे पता है कि पुराने कंपाइलर शून्य आकार के सरणियों के बारे में शिकायत करते हैं।
smcameron

3
मुझे यह पसंद है, हालांकि, आपको मॉलोक (ऑफसेट (एक्स, स्ट्र) + न्यूमबाइट्स) जैसे कुछ का उपयोग करना चाहिए अन्यथा पैडिंग और संरेखण मुद्दों के कारण चीजें गलत हो जाएंगी। उदाहरण आकार (संरचना X) 8 हो सकता है, 5. नहीं
फोजी

3
@ फोजी: मुझे वास्तव में नहीं लगता कि यह कोई समस्या होगी। चूँकि इस संस्करण में स्ट्रेट का 1 बाइट शामिल है str[1](नहीं str[]) sizeof(struct X)। यह भी शामिल है के बीच किसी भी गद्दी lenऔर str
इवान टेरान

2
@ रस्क़ी: यह नकारात्मक रूप से किसी चीज़ को कैसे प्रभावित करेगा? मान लीजिए कि के बाद "गद्दी" है str। ठीक है, जब मैं आवंटित sizeof(struct X) + 10करता हूं तो यह strप्रभावी रूप से 10 - sizeof(int)(या अधिक, क्योंकि हमने कहा था कि वहाँ पैडिंग है) बड़ा। यह ओवरले str और उसके बाद कोई भी पेडिंग है। इसका एकमात्र तरीका यह है कि इसमें कोई अंतर होगा, यदि कोई सदस्य है strजिसके बाद पूरी चीज को तोड़ता है, तो लचीले सदस्यों को अंतिम होना चाहिए। अंत में कोई भी पैडिंग केवल आवंटित किए जाने के लिए बहुत अधिक कारण होगा। कृपया एक विशिष्ट उदाहरण प्रदान करें कि यह वास्तव में कैसे गलत हो सकता है।
इवान टेरान

17

कक्षाओं के अनुकरण द्वारा सी के साथ ऑब्जेक्ट ओरिएंटेड कोड।

बस एक संरचना और फ़ंक्शन का एक सेट बनाएं जो उस पैरामीटर को पहले पैरामीटर के रूप में एक पॉइंटर लेते हैं।


2
क्या अब भी कुछ ऐसा है जो C ++ में C ++ का अनुवाद करता है, जैसे cfront इस्तेमाल किया जाता है?
MarkJ

11
यह शायद ही वस्तु अभिविन्यास है। वंशानुक्रम के साथ OO के लिए, आपको अपनी ऑब्जेक्ट संरचना में कुछ प्रकार के वर्चुअल फ़ंक्शन तालिका को जोड़ना होगा, जिसे "उप-वर्ग" द्वारा अधिभारित किया जा सकता है। इस उद्देश्य के लिए बहुत सारे आधे-अधूरे "सी विद क्लासेस" -स्टाइल फ्रेमवर्क हैं, लेकिन मैं इससे बाहर रहने की सलाह देता हूं।
EXDM69

यह कहने की जरूरत है। उसके लिए +1।
अमित एस

3
@ exDM69, ऑब्जेक्ट ओरिएंटेशन किसी समस्या के बारे में सोचने का एक तरीका है क्योंकि यह एक कोडिंग प्रतिमान है; आप इसे विरासत के बिना सफलतापूर्वक कर सकते हैं। C ++ में फुल बोर जंप करने से पहले मैंने कुछ प्रोजेक्ट्स पर ऐसा किया।
मार्क रैनसम


14

रिकॉर्ड को आसान बनाए रखने के लिए बेवकूफ मैक्रो ट्रिक का उपयोग करना।

#define COLUMNS(S,E) [(E) - (S) + 1]

typedef struct
{
    char studentNumber COLUMNS( 1,  9);
    char firstName     COLUMNS(10, 30);
    char lastName      COLUMNS(31, 51);

} StudentRecord;

11

एक वैरिएबल बनाने के लिए जिसे केवल सभी मॉड्यूलों में पढ़ा जाता है, केवल एक को छोड़कर जो इसमें घोषित किया गया है:

// Header1.h:

#ifndef SOURCE1_C
   extern const int MyVar;
#endif

// Source1.c:

#define SOURCE1_C
#include Header1.h // MyVar isn't seen in the header

int MyVar; // Declared in this file, and is writeable

// Source2.c

#include Header1.h // MyVar is seen as a constant, declared elsewhere

यह खतरनाक लगता है। ये घोषणा और परिभाषा हैं जो मेल नहीं खाते हैं। संकलन करते समय Source2.c, कंपाइलर मान सकता है कि MyVarकोई फ़ंक्शन कॉल करने पर भी नहीं बदलता है Source1.c। (ध्यान दें कि यह एक वास्तविक कॉन्स्टेबल चर के रूप में, एक पॉइंटर से कॉन्स में भिन्न होता है। उत्तरार्द्ध मामले में, पॉइंट-टू-ऑब्जेक्ट अभी भी एक अलग पॉइंटर के माध्यम से संशोधित किया जा सकता है।)
jilles

1
यह चर का उत्पादन नहीं करता है जो केवल कुछ संकलन इकाइयों में आसानी से होता है। यह अपरिभाषित व्यवहार पैदा करता है (आईएसओ 9899 का पी। 6.2.7.2 और पी। 6.7.3.5 देखें)।
एल्स हकल

8

बिट-शिफ्ट केवल 31 (32 बिट पूर्णांक पर) की शिफ्ट-राशि तक परिभाषित हैं।

यदि आप एक अभिकलन शिफ्ट करना चाहते हैं तो आपको उच्चतर शिफ्ट-वैल्यू के साथ काम करने की क्या आवश्यकता है? यहाँ है कैसे Theora वीडियो-कोडेक यह करता है:

unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
  return (a>>(v>>1))>>((v+1)>>1);
}

या बहुत अधिक पठनीय:

unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
  unsigned int halfshift = v>>1;
  unsigned int otherhalf = (v+1)>>1;

  return (a >> halfshift) >> otherhalf; 
}

इस तरह से शाखा का उपयोग करने की तुलना में ऊपर दिखाए गए तरीके से कार्य करना एक अच्छा सौदा है:

unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
  if (v<=31)
    return a>>v;
  else
    return 0;
}

... और जीसीसी वास्तव में यह :) +1 inlines
टिम पोस्ट

2
मेरी मशीन पर, gcc-4.3.2 एक cmov निर्देश (सशर्त चाल) का उपयोग करके दूसरे में शाखा से छुटकारा पाती है
एडम रोसेनफील्ड

3
"एक शाखा का उपयोग करने की तुलना में तेजी से एक अच्छा सौदा": अंतर यह है कि शाखा सभी मूल्यों के लिए सही है v, जबकि halfshiftट्रिक केवल 32-बिट आर्किटेक्चर पर स्वीकार्य सीमा को 63 और 64-बिट पर 127 को दोहराता है।
पास्कल क्यूक

8

परिमित राज्य मशीनों को लागू करने के कार्यों के लिए सूचक की घोषणा की।

int (* fsm[])(void) = { ... }

सबसे सुखद फायदा यह है कि सभी कोड पथों की जांच करने के लिए प्रत्येक उत्तेजना / राज्य को मजबूर करना सरल है।

एक एम्बेडेड सिस्टम में, मैं अक्सर इस तरह के एक टेबल को इंगित करने के लिए एक ISR मैप करता हूं और आवश्यकतानुसार (ISR के बाहर) इसे फिर से चलाता हूं।


इसके साथ एक तकनीक मुझे पसंद है, अगर आपके पास एक फ़ंक्शन है जिसे आरंभीकरण की आवश्यकता है, तो आप सूचक को इनिशियलाइज़ेशन रूटीन के लिए कॉल के साथ आरंभ करते हैं। जब वह चलता है, तो आखिरी काम यह करता है कि सूचक को वास्तविक फ़ंक्शन के लिए सूचक के साथ बदल दिया जाए, फिर उस फ़ंक्शन को कॉल करें। इस तरह, इनिशियलाइज़र को स्वचालित रूप से पहली बार फ़ंक्शन कहा जाता है, और वास्तविक फ़ंक्शन को बाद में हर बार कॉल किया जाता है।
TMN

7

एक और अच्छा प्री-प्रोसेसर "ट्रिक" डिबगिंग एक्सप्रेशन को प्रिंट करने के लिए "#" कैरेक्टर का उपयोग करना है। उदाहरण के लिए:

#define MY_ASSERT(cond) \
  do { \
    if( !(cond) ) { \
      printf("MY_ASSERT(%s) failed\n", #cond); \
      exit(-1); \
    } \
  } while( 0 )

संपादित करें: नीचे दिया गया कोड केवल C ++ पर काम करता है। Smcameron और इवान टेरान के लिए धन्यवाद।

हां, संकलन का समय हमेशा महान होता है। इसे इस प्रकार भी लिखा जा सकता है:

#define COMPILE_ASSERT(cond)\
     typedef char __compile_time_assert[ (cond) ? 0 : -1]

COMPILE_ASSERT मैक्रो का उपयोग दो बार नहीं किया जा सकता है, क्योंकि यह टाइपसेफ के साथ नाम स्थान को प्रदूषित करता है, और दूसरा उपयोग प्राप्त होता है: त्रुटि: टाइप किए गए '' _compile_time_assert '' का पुन: निर्धारण
smereron

क्या आपने वास्तव में यह कोशिश की थी? आप "टाइफाइड फू;" जितनी बार चाहें उतनी बार। इसी तरह आप पूर्वनिर्धारण करते हैं। मैंने इसे 2.5 वर्षों के लिए उपयोग किया है कई संकलक पर, दोनों gcc, VC और एक एम्बेडेड वातावरण के लिए एक संकलक, और कभी भी किसी भी कठिनाइयों का सामना नहीं करना पड़ा।
गिलाद नोर

मैं सी पूर्वप्रक्रमक ... :( नफरत
Hasen

1
हां, मैंने कोशिश की। मैंने संकलक से त्रुटि संदेश को काट दिया और चिपकाया, जो कि जीसीसी था।
smcameron

1
@ गिल्ड: यह सी + + में कानूनी रूप से टाइप किएडिफ्स के लिए कानूनी है, लेकिन सी में नहीं।
Evan Teran

6

मैं वास्तव में इसे एक पसंदीदा चाल नहीं कहूंगा, क्योंकि मैंने कभी इसका उपयोग नहीं किया है, लेकिन डफ के उपकरण के उल्लेख ने मुझे इस लेख के बारे में याद दिलाया कि मैं कोरटाइन को सी में लागू करने के बारे में हूं। यह मुझे हमेशा चकली देता है, लेकिन मुझे यकीन है कि यह हो सकता है कुछ समय के लिए उपयोगी हो।


मैंने वास्तव में इस तकनीक का उपयोग कोड ड्राइविंग को आश्रित अतुल्यकालिक I / O अस्पष्ट मानव-पठनीय के अनुक्रम को बनाने के लिए किया है। मुख्य अंतर यह है कि मैं एक staticचर में coroutine राज्य को संग्रहीत नहीं करता हूं , बल्कि एक गतिशील रूप से एक संरचना आवंटित करता है और उस पॉइंटर को coroutine फ़ंक्शन में पास करता है। मैक्रोज़ का एक गुच्छा इसे और अधिक स्वादिष्ट बनाता है। यह अच्छा नहीं है, लेकिन सभी स्थानों पर कूदने वाले एसिंक्स / कॉलबैक संस्करण से बेहतर है। swapcontext()अगर मैं हालांकि मैं हरे रंग के धागे ( * निक्स के माध्यम से ) का उपयोग करूँगा ।
19

6
#if TESTMODE == 1    
    debug=1;
    while(0);     // Get attention
#endif

जबकि (0); कार्यक्रम पर कोई प्रभाव नहीं पड़ता है, लेकिन कंपाइलर "यह कुछ नहीं करता है" के बारे में एक चेतावनी जारी करेगा, जो मुझे आक्रामक रेखा को देखने के लिए प्राप्त करने के लिए पर्याप्त है और फिर वास्तविक कारण देखें जो मैं इस पर ध्यान देना चाहता था।


9
क्या आप इसके बजाय #warning का उपयोग नहीं कर सकते?
स्टेफानो बोरीनी

जाहिर है, मैं कर सकता था। यह पूरी तरह से मानक नहीं है, लेकिन यह उन कंपाइलरों में काम करता है जो मैं उपयोग करता हूं। दिलचस्प है, एम्बेडेड कंपाइलर ने #define का अनुवाद किया, जबकि gcc ने नहीं किया।
गब्बरू

6

मैं xor हैक्स का प्रशंसक हूं:

तीसरे टेम्परेचर पॉइंटर के बिना स्वैप 2 पॉइंट:

int * a;
int * b;
a ^= b;
b ^= a;
a ^= b;

या मुझे वास्तव में केवल एक पॉइंटर के साथ xor लिंक्ड सूची पसंद है। (Http://en.wikipedia.org/wiki/XOR_linked_list)

लिंक की गई सूची में प्रत्येक नोड पिछले नोड और अगले नोड का Xor है। आगे बढ़ने के लिए, नोड्स का पता निम्नलिखित तरीके से पाया जाता है:

LLNode * first = head;
LLNode * second = first.linked_nodes;
LLNode * third = second.linked_nodes ^ first;
LLNode * fourth = third.linked_nodes ^ second;

आदि।

या पीछे की ओर पार करने के लिए:

LLNode * last = tail;
LLNode * second_to_last = last.linked_nodes;
LLNode * third_to_last = second_to_last.linked_nodes ^ last;
LLNode * fourth_to_last = third_to_last.linked_nodes ^ second_to_last;

आदि।

जबकि बहुत उपयोगी नहीं है (आप एक मनमाना नोड से ट्रैवर्सिंग शुरू नहीं कर सकते हैं) मुझे यह बहुत अच्छा लगता है।


5

यह पुस्तक 'पर्याप्त रस्सी को पैर में खुद को मारने के लिए' से आई है:

हेडर डिक्लेयर में

#ifndef RELEASE
#  define D(x) do { x; } while (0)
#else
#  define D(x)
#endif

अपने कोड में परीक्षण विवरण जगह जैसे:

D(printf("Test statement\n"));

जब मैक्रो की सामग्री कई स्टेटमेंट तक विस्तारित हो जाती है, तो डू / करते समय मदद मिलती है।

यदि कंपाइलर के लिए '-D RELEASE' झंडे का उपयोग नहीं किया गया है तो केवल स्टेटमेंट प्रिंट किया जाएगा।

फिर आप उदा। ध्वज को अपने मेकफिल आदि में पास करें।

यह सुनिश्चित नहीं है कि यह विंडोज़ में कैसे काम करता है लेकिन * निक्स में यह अच्छी तरह से काम करता है


RELEASE को परिभाषित करने पर आप D (x) से {} तक का विस्तार करना चाह सकते हैं, ताकि यदि वह कथन के साथ अच्छा लगे। अन्यथा "अगर (ए) डी (एक्स);" जब आप RELEASE परिभाषित करेंगे तो सिर्फ "if (a)" तक विस्तार होगा। यही कारण है कि आप कुछ अच्छे कीड़े दे देंगे
MarkJ

3
@ मर्कज: नहीं। जिस तरह से यह है, "अगर (ए) डी (एक्स);" "यदि (ए);" जो पूरी तरह से ठीक है। यदि आपके पास D (x) का विस्तार {} से होता है, तो "if (a) if (b) D (x); और पू ());" INCORRECTLY का विस्तार "अगर (a) अगर (b) {}; और foo ();" होगा, तो "if foo ()" के साथ दूसरा होगा अगर पहले की बजाय दूसरा।
एडम रोसेनफील्ड

ईमानदार होने के लिए, मैं ज्यादातर प्रिंट स्टेटमेंट्स के परीक्षण के लिए इस मैक्रो का उपयोग करता हूं, या यदि मेरे पास एक सशर्त बयान था, तो मैं इसे सभी को संलग्न करूंगा। डी (अगर (ए) फू (;);
सिमोन वाकर

1
@AdamRosenfield: #define D(x) do { } while(0)इसके बजाय का उपयोग करके उस मामले को संभालता है (और उस शाखा पर लागू किया जा सकता है जो xनिरंतरता के लिए आवेषण करता है )
rpetrich

3

जंग खाए वास्तव में ccan में बिल्ड कंडीशंस का एक पूरा सेट का निर्माण किया, बिल्ड एस्टर मॉड्यूल की जाँच करें:

#include <stddef.h>
#include <ccan/build_assert/build_assert.h>

struct foo {
        char string[5];
        int x;
};

char *foo_string(struct foo *foo)
{
        // This trick requires that the string be first in the structure
        BUILD_ASSERT(offsetof(struct foo, string) == 0);
        return (char *)foo;
}

वास्तविक हेडर में कई अन्य सहायक मैक्रो हैं, जो जगह में गिराना आसान है।

मैं कोशिश करता हूं, मेरी पूरी कोशिश हो कि ज्यादातर इनलाइन फंक्शन्स में चिपककर डार्क साइड (और प्रीप्रोसेसर दुर्व्यवहार) का विरोध कर सकूं, लेकिन मैं आपके बताए तरह चतुर, उपयोगी मैक्रों का आनंद लेता हूं।


हाँ, मैं हाल ही में ccan में आया था, और कुछ कोड के योगदान पर विचार कर रहा था, लेकिन अभी तक मेरे सिर को "ccan way" के आसपास नहीं लपेटा है। हालांकि इस लिंक के लिए धन्यवाद, ccan में देखने के लिए और अधिक प्रेरणा, जो मुझे वास्तव में आशा है कि कुछ कर्षण मिलता है।
smcameron

खैर, मैं 'ccan way' पर बहुत चिंतित नहीं होऊंगा, जब तक कि इसे और अधिक स्थापित नहीं किया जाता ... अभी ccan-lint को GSOC प्रोजेक्ट के रूप में प्रस्तावित किया जा रहा है। यह एक छोटा सा और नहीं बल्कि अनुकूल समूह .. और डंप के टुकड़े करने के लिए :) एक महान जगह
टिम पोस्ट

BTW, मैंने देखा कि रस्टी की BuILD_ASSERT लाइनक्स कर्नेल (अचंभित) से मैक्रो की तरह है, लेकिन "नोट्स" (या बैंग्स, या! ') में से एक की कमी है और यह देखते हुए, मुझे लगता है कि मेरे द्वारा पोस्ट किए गए मैक्रो का मेरा उदाहरण उपयोग है। गलत। होना चाहिए था: "BUILD_BUG_ON ((sizeof) (संरचना रहस्य)% 8))"
smcameron

3

इस तरह के सामान के लिए दो अच्छी स्रोत पुस्तकें हैं , प्रोग्रामिंग का अभ्यास और ठोस कोड लिखना । उनमें से एक (मुझे याद नहीं है जो कहता है): # enf # को पसंद करें जहाँ आप कर सकते हैं, क्योंकि कंपाइलर द्वारा एनम की जाँच की जाती है।


1
AFAIK, C89 / 90 में एनम के लिए कोई टाइपकास्टिंग नहीं है। एनम बस किसी भी अधिक सुविधाजनक #defines हैं।
सीएसचोल

पृष्ठ 39 के नीचे, दूसरा ED K & R। जांच के लिए कम से कम अवसर है।
जोनाथन वॉटम

3

सी के लिए विशिष्ट नहीं है, लेकिन मुझे हमेशा XOR ऑपरेटर पसंद आया है। एक अच्छी बात यह है कि "एक अस्थायी मूल्य के बिना स्वैप" हो सकता है:

int a = 1;
int b = 2;

printf("a = %d, b = %d\n", a, b);

a ^= b;
b ^= a;
a ^= b;

printf("a = %d, b = %d\n", a, b);

परिणाम:

ए = १, बी = २

a = 2, b = 1


a = 1; बी = 2; a = a + b; b = ab; a = ab; एक ही परिणाम भी देता है
ग्राम्बोट

यह भी a और b स्वैप करेगा: a ^ = b ^ = a ^ = b;
विक्टाट

@ TheCapn: इसके अलावा अतिप्रवाह हो सकता है, हालांकि।
माइकल फौकरीस


2

मुझे container_ofसूचियों में उदाहरण के लिए प्रयुक्त अवधारणा पसंद है । मूल रूप से, आपको निर्दिष्ट करने की आवश्यकता नहीं है nextऔरlast प्रत्येक संरचना के लिए फ़ील्ड की जो सूची में होगी। इसके बजाय, आप सूची संरचना हेडर को वास्तविक लिंक्ड आइटमों में जोड़ते हैं।

include/linux/list.hवास्तविक जीवन के उदाहरणों पर एक नज़र डालें ।


1

मुझे लगता है कि userdata संकेत का उपयोग बहुत साफ है। एक फैशन खोने जमीन आजकल। यह बहुत सी सुविधा नहीं है, लेकिन सी में उपयोग करने के लिए बहुत आसान है।


1
काश कि मैं समझ पाती कि आपका यहां क्या मतलब था। आप और समझा सकते हैं? उपयोगकर्ताडटा सूचक क्या है?
ज़ेन लिंक्स

1
Plz यहाँ देखें stackoverflow.com/questions/602826/…
epatel

यह मुख्य रूप से कॉलबैक के लिए है। यह कुछ डेटा है जिसे आप कॉल बैक होने पर हर बार आपको वापस देना चाहेंगे। विशेष रूप से C ++ के इस पॉइंटर को कॉलबैक में पास करने के लिए उपयोगी है ताकि आप किसी ईवेंट को ऑब्जेक्ट टाई कर सकें।
इवान टेरन

आह येस। धन्यवाद। मैं इसका भरपूर उपयोग करता हूं, लेकिन मैंने इसे कभी नहीं बुलाया।
ज़ेन लिंक्स

1

मैं प्री-कंपाइलर कोड उत्पन्न करने देने के लिए X-Macros का उपयोग करता हूं । वे त्रुटि मानों और संबंधित त्रुटि स्ट्रिंग को एक स्थान पर परिभाषित करने के लिए विशेष रूप से उपयोगी हैं, लेकिन वे इससे बहुत आगे जा सकते हैं।


1

हमारे कोडबेस के पास एक ट्रिक है

#ifdef DEBUG

#define my_malloc(amt) my_malloc_debug(amt, __FILE__, __LINE__)
void * my_malloc_debug(int amt, char* file, int line)
#else
void * my_malloc(int amt)
#endif
{
    //remember file and line no. for this malloc in debug mode
}

जो डिबग मोड में मेमोरी लीक की ट्रैकिंग के लिए अनुमति देता है। मुझे हमेशा लगता था कि यह अच्छा था।


1

मैक्रोज़ के साथ मज़ा:

#define SOME_ENUMS(F) \
    F(ZERO, zero) \
    F(ONE, one) \
    F(TWO, two)

/* Now define the constant values.  See how succinct this is. */

enum Constants {
#define DEFINE_ENUM(A, B) A,
    SOME_ENUMS(DEFINE_ENUMS)
#undef DEFINE_ENUM
};

/* Now a function to return the name of an enum: */

const char *ToString(int c) {
    switch (c) {
    default: return NULL; /* Or whatever. */
#define CASE_MACRO(A, B) case A: return #b;
     SOME_ENUMS(CASE_MACRO)
#undef CASE_MACRO
     }
}

0

यहां एक उदाहरण है कि कैसे सी कोड को इस बात से अनभिज्ञ बनाया जाए कि ऐप चलाने के लिए वास्तव में एचडब्ल्यू का क्या उपयोग किया जाता है। Main.c सेटअप करता है और फिर किसी भी कंपाइलर / आर्क पर फ्री लेयर को लागू किया जा सकता है। मुझे लगता है कि सी कोड को थोड़ा अमूर्त करने के लिए यह काफी साफ-सुथरा है, इसलिए यह स्पेशल होने के लिए नहीं है।

यहां एक संपूर्ण संकलन उदाहरण जोड़ना।

/* free.h */
#ifndef _FREE_H_
#define _FREE_H_
#include <stdio.h>
#include <string.h>
typedef unsigned char ubyte;

typedef void (*F_ParameterlessFunction)() ;
typedef void (*F_CommandFunction)(ubyte byte) ;

void F_SetupLowerLayer (
F_ParameterlessFunction initRequest,
F_CommandFunction sending_command,
F_CommandFunction *receiving_command);
#endif

/* free.c */
static F_ParameterlessFunction Init_Lower_Layer = NULL;
static F_CommandFunction Send_Command = NULL;
static ubyte init = 0;
void recieve_value(ubyte my_input)
{
    if(init == 0)
    {
        Init_Lower_Layer();
        init = 1;
    }
    printf("Receiving 0x%02x\n",my_input);
    Send_Command(++my_input);
}

void F_SetupLowerLayer (
    F_ParameterlessFunction initRequest,
    F_CommandFunction sending_command,
    F_CommandFunction *receiving_command)
{
    Init_Lower_Layer = initRequest;
    Send_Command = sending_command;
    *receiving_command = &recieve_value;
}

/* main.c */
int my_hw_do_init()
{
    printf("Doing HW init\n");
    return 0;
}
int my_hw_do_sending(ubyte send_this)
{
    printf("doing HW sending 0x%02x\n",send_this);
    return 0;
}
F_CommandFunction my_hw_send_to_read = NULL;

int main (void)
{
    ubyte rx = 0x40;
    F_SetupLowerLayer(my_hw_do_init,my_hw_do_sending,&my_hw_send_to_read);

    my_hw_send_to_read(rx);
    getchar();
    return 0;
}

4
विस्तार से देखभाल, शायद एक व्यावहारिक उपयोग की व्याख्या?
लियोनार्डो हरेरा

एक wxample के रूप में अगर मुझे सोम HW इंटरफ़ेस का उपयोग करके एक परीक्षण कार्यक्रम लिखना है जो अंत में इंटरुप बनाता है। तब इस मॉड्यूल को सिग्नल / इंटरप्ट हैंडलर के रूप में सामान्य दायरे से बाहर किसी फ़ंक्शन को निष्पादित करने के लिए सेटअप किया जा सकता है।
eaanon01

0
if(---------)  
printf("hello");  
else   
printf("hi");

रिक्त स्थान भरें ताकि उत्पादन में न तो हैलो और न ही हाय दिखाई दे।
उत्तर:fclose(stdout)


आप {}टूलबार बटन के साथ कोड को प्रारूपित कर सकते हैं (मैंने इसे आपके लिए किया है)। "भाव" बटन व्हाट्सएप नहीं रखता है या सिंटैक्स हाइलाइटिंग लागू नहीं करता है।
अल्वारो गोंजालेज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.