सी
पृष्ठभूमि की कहानी
मेरी पत्नी को परिवार से एक बिल्ली विरासत में मिली। † दुर्भाग्य से, मैं जानवरों के लिए बहुत एलर्जी हूँ। बिल्ली अच्छी तरह से अपने प्रमुख अतीत में थी और हमें मिलने से पहले ही उसे अलग कर दिया जाना चाहिए था, लेकिन वह अपने भावुक मूल्य के कारण इससे छुटकारा पाने के लिए खुद को नहीं ला सकी। मैं अंत करने की योजना रची मेरी अपनी पीड़ा।
हम एक विस्तारित छुट्टी पर जा रहे थे, लेकिन वह पशु चिकित्सक के कार्यालय में बिल्ली पर चढ़ना नहीं चाहता था। वह इसके बारे में चिंतित थी कि यह बीमारी से जूझ रहा है या गलत व्यवहार किया जा रहा है। मैंने एक स्वचालित बिल्ली फीडर बनाया ताकि हम इसे घर पर छोड़ सकें। मैंने सी में माइक्रोकंट्रोलर के फर्मवेयर को लिखा था। फाइल में main
नीचे दिए गए कोड के समान दिख रहा था ।
हालाँकि, मेरी पत्नी भी एक प्रोग्रामर है और बिल्ली के प्रति मेरी भावनाओं को जानती है, इसलिए उसने इसे घर पर छोड़ने के लिए सहमत होने से पहले एक कोड-समीक्षा पर जोर दिया। उसकी कई चिंताएँ थीं, जिनमें शामिल हैं:
main
मानकों के अनुरूप हस्ताक्षर नहीं है (एक होस्ट किए गए कार्यान्वयन के लिए)
main
मान वापस नहीं करता है
tempTm
के malloc
बजाय बुलाया गया था के बाद से uninitialized प्रयोग किया जाता हैcalloc
- वापसी का मूल्य
malloc
नहीं डाला जाना चाहिए
- माइक्रोकंट्रोलर समय गलत या रोल ओवर हो सकता है (Y2K या यूनिक्स समय 2038 समस्याओं के समान)
elapsedTime
चर पर्याप्त रेंज नहीं हो सकता है
इसने बहुत आश्वस्त किया, लेकिन वह आखिरकार इस बात पर सहमत हो गई कि थिसिस विभिन्न कारणों से समस्या नहीं थी (यह दुख नहीं था कि हमें अपनी उड़ान के लिए पहले ही देर हो चुकी थी)। चूंकि लाइव परीक्षण का समय नहीं था, उसने कोड को मंजूरी दे दी और हम छुट्टी पर चले गए। जब हम कुछ हफ़्ते बाद लौटे, तो मेरी बिल्ली का दुख खत्म हो गया (हालांकि परिणामस्वरूप अब मैं बहुत अधिक हो गया हूं)।
, पूरी तरह से काल्पनिक परिदृश्य, कोई चिंता नहीं।
कोड
#include <time.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
//#include "feedcat.h"
// contains extern void FeedCat(struct tm *);
// implemented in feedcat.c
// stub included here for demonstration only
#include <stdio.h>
// passed by pointer to avoid putting large structure on stack (which is very limited)
void FeedCat(struct tm *amPm)
{
if(amPm->tm_hour >= 12)
printf("Feeding cat dinner portion\n");
else
printf("Feeding cat breakfast portion\n");
}
// fallback value calculated based on MCU clock rate and average CPI
const uintmax_t FALLBACK_COUNTER_LIMIT = UINTMAX_MAX;
int main (void (*irqVector)(void))
{
// small stack variables
// seconds since last feed
int elapsedTime = 0;
// fallback fail-safe counter
uintmax_t loopIterationsSinceFeed = 0;
// last time cat was fed
time_t lastFeedingTime;
// current time
time_t nowTime;
// large struct on the heap
// stores converted calendar time to help determine how much food to
// dispense (morning vs. evening)
struct tm * tempTm = (struct tm *)malloc(sizeof(struct tm));
// assume the cat hasn't been fed for a long time (in case, for instance,
// the feeder lost power), so make sure it's fed the first time through
lastFeedingTime = (size_t)(-1);
while(1)
{
// increment fallback counter to protect in case of time loss
// or other anomaly
loopIterationsSinceFeed++;
// get current time, write into to nowTime
time(&nowTime);
// calculate time since last feeding
elapsedTime = (int)difftime(nowTime, lastFeedingTime);
// get calendar time, write into tempTm since localtime uses an
// internal static variable
memcpy(&tempTm, localtime(&nowTime), sizeof(struct tm));
// feed the cat if 12 hours have elapsed or if our fallback
// counter reaches the limit
if( elapsedTime >= 12*60*60 ||
loopIterationsSinceFeed >= FALLBACK_COUNTER_LIMIT)
{
// dispense food
FeedCat(tempTm);
// update last feeding time
time(&lastFeedingTime);
// reset fallback counter
loopIterationsSinceFeed = 0;
}
}
}
अपरिभाषित व्यवहार:
उन लोगों के लिए जो खुद को यूबी खोजने से परेशान नहीं करना चाहते हैं:
इस कोड में निश्चित रूप से स्थानीय-विशिष्ट, अनिर्दिष्ट और कार्यान्वयन-परिभाषित व्यवहार है, लेकिन यह सभी सही ढंग से काम करना चाहिए। समस्या कोड की निम्न पंक्तियों में है: पॉइंटर को उस ऑब्जेक्ट के बजाय
struct tm * tempTm //...
//...
memcpy(&tempTm, localtime(&nowTime), sizeof(struct tm));
memcpy
अधिलेखित करता tempTM
है, जो स्टैक को मिटाता है। यह अन्य चीजों के अलावा ओवरराइट करता है, elapsedTime
और loopIterationsSinceFeed
। यहाँ एक उदाहरण रन है जहाँ मैंने मूल्यों को छापा है:
pre-smash : elapsedTime=1394210441 loopIterationsSinceFeed=1
post-smash : elapsedTime=65 loopIterationsSinceFeed=0
बिल्ली को मारने की संभावना:
- विवश निष्पादन पर्यावरण और निर्माण श्रृंखला को देखते हुए, अपरिभाषित व्यवहार हमेशा होता है।
- इसी तरह, अपरिभाषित व्यवहार हमेशा बिल्ली के फीडर को उद्देश्य के रूप में काम करने से रोकता है (या यों कहें, इसे "इच्छित रूप से" काम करने की अनुमति देता है)।
- यदि फीडर काम नहीं करता है, तो यह बहुत संभावना है कि बिल्ली मर जाएगी। यह एक बिल्ली नहीं है जो खुद के लिए रोक सकता है, और मैं पड़ोसी को उस पर देखने के लिए कहने में विफल रहा।
मुझे लगता है कि बिल्ली संभावना 0.995 के साथ मर जाती है ।