2010-05-14 12 views
6

मैं एक समारोह irc_sendline कि printf की तरह कहा जा सकता है है सकते हैंसी चर तर्क पुनर्रचना

irc_sendline(s, "A strange game.\nThe only %s is not to play.", "winning move"); 

यह पूरी तरह से काम करता है, लेकिन मैं इसके कार्यान्वयन के साथ खुश नहीं हूँ:

int irc_sendline(irc *iobj, char *msg, ...) 
{ 
    char tmp_msg[BUFSIZE], fmsg[BUFSIZE]; 
    va_list args; 
    int len; 

    va_start(args, msg); 

    strncpy(tmp_msg, msg, BUFSIZE); 
    strncat(tmp_msg, "\r\n", BUFSIZE); 

    len = vsnprintf(fmsg, BUFSIZE, tmp_msg, args); 
    len = send(iobj->fd, fmsg, len, 0); 

    return len; 
} 

तुम देखो, मैं यहाँ 2 "अस्थायी" बफर का उपयोग कर रहा हूं, क्योंकि मुझे पहले मूल संदेश को फ़ंक्शन तर्क से "अस्थायी बफर में" \ r \ n "जोड़ने के लिए प्रतिलिपि बनाना है, और उसके बाद उस अस्थायी बफर को पर अस्थायी प्रतिलिपि बनाना अस्थायी buffe फंक्शन कॉल से प्रदान किए गए तर्कों के साथ वास्तविक स्वरूपण करने के लिए, और केवल THEN मैं सामान को अपने रास्ते पर भेज सकता हूं।

मैं इस क्लीनर को बेहतर कैसे बना सकता हूं?


यहां सभी इनपुट के लिए धन्यवाद, मैंने सोचा कि मेरी एकमात्र समस्या वहां गड़बड़ थी, लेकिन वास्तव में यह एक टिकिंग टाइमबॉम्ब था! मेरा नया फ़ंक्शन इस तरह दिखता है:

int irc_sendline(irc *iobj, char *msg, ...) 
{ 
    char buffer[BUFSIZE]; 
    va_list args; 
    int res_str_len; 
    int sent; 

    va_start(args, msg); 

    res_str_len = vsnprintf(buffer, BUFSIZE, msg, args); 

    sent = send(iobj->fd, buffer, res_str_len, 0); 
    sent += send(iobj->fd, "\r\n", 2, 0); 

    return sent; 
} 

यदि मैं कर सकता, तो मैं यहां कई उत्तरों स्वीकार करता हूं, लेकिन मेह।

+0

आपका कोड (मेरा उत्तर देखें) 'strncpy' के गलत उपयोग की वजह से टूट गया है काटना चाहते हैं। – AnT

+0

'strncat' का उपयोग भी टूटा हुआ है। 'strncat' ऐसा नहीं करता जो आपको लगता है कि यह करता है। 'BUFSIZE-2' के लिए – AnT

उत्तर

5

डेटा प्रारूपित करने के लिए पहले vsnprintf का उपयोग करें, फिर उसके परिणामस्वरूप "\ r \ n" संलग्न करें। वैकल्पिक रूप से, "\ r \ n" भेजने के लिए बस send पर दूसरी कॉल का उपयोग करें।

1

\r\n के बाद से स्वरूपित स्ट्रिंग के अंत में खत्म करने के लिए, क्यों बाद में नकल नहीं जा रहा है:

va_start(args, msg); 
len = vsnprintf(fmsg, BUFSIZE, msg, args); 
strncat(fmsg, "\r\n", BUFSIZE - strlen(fmsg) - 1); 

ध्यान दें कि मैं भी तर्क strncat को तय की।

0

जब तक आप स्ट्रैट के लिए संदेश का उपयोग नहीं करना चाहते थे (असुरक्षित और बुराई क्योंकि आप स्ट्रिंग आकार नहीं जानते हैं), मुझे लगता है कि आपको 2 बफर के साथ रहना होगा।

एक तरफ, मैं strncpy (..., BUFSIZE-2) पर विचार करता हूं ताकि \ r \ n हमेशा इसे आपके संदेशों पर बना देता है और इसलिए तार हमेशा लपेटते हैं।

+0

+1। –

+0

BUFSIZE चीज़ को इंगित करने के लिए धन्यवाद! मैंने यह नहीं देखा कि बिलकुल मुझे खत्म कर सकता था। – LukeN

+0

आप अभी भी भूल रहे हैं कि अगर बफर बहुत छोटा है तो 'stncpy' स्ट्रिंग में शून्य टर्मिनेटर नहीं जोड़ता है। 'BUFSIZE-2' इसे ठीक नहीं करेगा। जब भी बफर एंड प्रारूप प्रारूप स्ट्रिंग द्वारा मारा जाता है तो आपका कोड क्रैश हो जाएगा। – AnT

3

सबसे पहले, यदि आप "क्लीनर" में रुचि रखते हैं, तो strncpy का उपयोग करना बंद करें। भ्रामक नाम (और लोकप्रिय धारणा के विपरीत) के बावजूद, यह सीमित लंबाई वाली स्ट्रिंग प्रतिलिपि फ़ंक्शन नहीं है। यह कहना सुरक्षित है कि strncpy एक ऐसा फ़ंक्शन है जिसका आजकल कोई व्यावहारिक उपयोग नहीं है। जब आप कोड में उपयोग किए गए strncpy देखते हैं, तो "क्लीनर" तुरंत प्रश्न से बाहर हो जाता है (मामलों के गायब होने वाले संकीर्ण सेट से strncpy वास्तव में इसका उपयोग किया जाना था)।

वास्तव में, अपने कोड विशेष रूप से टूट गया है क्योंकि आप strncpy प्रयोग किया है: अगर प्रारूप स्ट्रिंग की लंबाई बफर की लंबाई से अधिक है, strncpyपरिणाम को समाप्त अशक्त चरित्र संलग्न नहीं है, जिसका अर्थ है कि बाद में strncat कॉल दुर्घटनाग्रस्त हो जाएगा (सबसे अच्छा)।

सीमित लंबाई प्रतिलिपि फ़ंक्शन मानक लाइब्रेरी में मौजूद नहीं है, लेकिन इसे अक्सर strlcpy नाम के कार्यान्वयन द्वारा प्रदान किया जाता है। यदि आप जिस कार्यान्वयन का उपयोग कर रहे हैं वह एक प्रदान नहीं करता है - स्वयं को लिखें और इसका उपयोग करें।

strncat: strncat के गलत उपयोग के कारण आपका कोड भी टूटा हुआ है अंतिम शब्द के रूप में पूर्ण बफर की लंबाई नहीं लेता है। इसके बजाय, strncat बफर के शेष की लंबाई की अपेक्षा करता है। इसलिए, यदि आप strncat का उपयोग करना चाहते हैं, तो आपको पिछली प्रतिलिपि के बाद बफर के अंत में कितनी जगह छोड़ी गई थी, इसकी गणना करनी होगी। फिर भी, strncatstrncpy से अधिक उपयोगी है, तो आप गैर-मानक (लेकिन अक्सर कार्यान्वयन द्वारा प्रदान किए गए) फ़ंक्शन strlcat का उपयोग करने से बेहतर हो सकते हैं, जो वास्तव में strncat काम करने के तरीके को काम करता है।

दूसरा, अग्रिम में \r\n भाग जोड़ने की बजाय, आप इसे बाद में क्यों नहीं करते? इस तथ्य का प्रयोग करें कि vsnprintf आउटपुट बफर में लिखे गए अक्षरों की संख्या देता है और vsnprintf समाप्त होने के बाद अंत में \r, \n और \0 वर्णों को जोड़ता है। उस उद्देश्य के लिए आपको strncat का उपयोग करने की आवश्यकता नहीं है। बस पात्रों को सीधे बफर में लिखें, सुनिश्चित करें कि, आप सीमा पार नहीं करते हैं।

+0

चेतावनी के लिए धन्यवाद (उनमें से 3 वास्तव में :), मैं वर्तमान में इस मुद्दे पर देख रहा हूं, और ऐसा लगता है कि मुझे अपना खुद का strlcpy लिखना है, क्योंकि लिनक्स इसे प्रदान नहीं करता है। Strncpy मामले पर - तो यह तोड़ दिया गया है क्योंकि यह लक्ष्य स्ट्रिंग लंबे समय तक/गंतव्य स्ट्रिंग के रूप में \ NUL संलग्न नहीं करेगा? – LukeN

+0

सबसे पहले, हाँ, स्ट्रिंग लंबा होने पर यह '\ 0' संलग्न नहीं होता है। दूसरा, यह स्ट्रिंग छोटा है, जो पूरी तरह से अनावश्यक है, यह शून्य के साथ बफर के पूरे शेष को भर देता है। एक बार फिर, 'strncpy' एक ऐसा फ़ंक्शन नहीं है जिसे शून्य-समाप्त तारों के लिए बनाया गया था। यह एक ऐसा फ़ंक्शन है जो यूनिक्स फ़ाइल सिस्टम के पुराने संस्करण में तथाकथित "निश्चित चौड़ाई" तारों का समर्थन करने के लिए एक पूरी तरह से अलग उद्देश्य के लिए बनाया गया था। आप इसके बारे में यहां और अधिक पढ़ सकते हैं: http://stackoverflow.com/questions/1453876/why-does-strncpy-not-null-terminate – AnT

+0

इसे साफ़ करने के लिए धन्यवाद, अब मुझे याद है कि मैंने स्पष्ट रूप से मेरे तारों को शून्य-समाप्त क्यों किया कुछ अन्य कार्यक्रम जो strncpy का इस्तेमाल किया। – LukeN

0

आपके कोड के साथ एक बड़ी समस्या - vsnprintf बफर में रखे गए वर्णों की संख्या लौटाती है, यदि यह असीम रूप से बड़ी थी, जो बफर पर्याप्त नहीं है तो BUFSIZE से बड़ा हो सकता है। तो यदि आपके पास एक संदेश है जो बहती है, तो आप अपने बफर के अंत के बाद से यादृच्छिक कचरा भेजना समाप्त कर देंगे। आप vprintf के बाद एक लाइन

if (res_str_len >= BUFSIZE) res_str_len = BUFSIZE-1 

जोड़ने की जरूरत है, तो आप वास्तव में संदेश

संबंधित मुद्दे