2009-06-14 10 views
13

ऐसा लगता है कि strtol() और strtod() प्रभावी रूप से अनुमति देते हैं (और बल) यदि आप एक स्ट्रिंग में constness दूर कास्ट करने के लिए:स्ट्रेटोल हैं, स्ट्रैट असुरक्षित हैं?

#include <stdlib.h> 
#include <stdio.h> 

int main() { 
    const char *foo = "Hello, world!"; 
    char *bar; 
    strtol(foo, &bar, 10); // or strtod(foo, &bar); 
    printf("%d\n", foo == bar); // prints "1"! they're equal 
    *bar = 'X'; // segmentation fault 
    return 0; 
} 

ऊपर, मैं प्रदर्शन नहीं किया था किसी भी अपने आप को डाले। हालांकि, strtol() मूल रूप से मेरे const char * को मेरे लिए char * में किसी भी चेतावनी या किसी भी चीज़ के बिना डाला गया। (वास्तव में, यह आपको bar को const char * के रूप में टाइप करने की अनुमति नहीं देगा, और इसलिए असुरक्षित परिवर्तन को प्रकार में मजबूर करता है।) क्या यह वास्तव में खतरनाक नहीं है?

उत्तर

13

मुझे लगता है कि विकल्प खराब था। मान लीजिए प्रोटोटाइप const जोड़ने के लिए बदल गया:

char str[] = "12345xyz"; // non-const 
char *endptr; 
lont result = strtol(str, &endptr, 10); 
*endptr = '_'; 
printf("%s\n", str); // expected output: 12345_yz 

लेकिन क्या होता है जब हम इस कोड को संकलित करने के लिए प्रयास करें:

long int strtol(const char *nptr, const char **endptr, int base); 

अब, हम एक गैर निरंतर स्ट्रिंग पार्स रखना चाहते हैं? एक कंपाइलर त्रुटि! यह बल्कि गैर-सहज ज्ञान युक्त है, लेकिन आप char ** को const char ** पर निहित रूप से परिवर्तित नहीं कर सकते हैं। क्यों विस्तृत विवरण के लिए C++ FAQ Lite देखें। यह तकनीकी रूप से सी ++ के बारे में बात कर रहा है, लेकिन तर्क सी/सी ++ में सी के लिए समान रूप से मान्य हैं, आपको केवल "पॉइंटर से टाइप" से पॉइंटर से constटाइप "उच्चतम स्तर पर निहित रूप से परिवर्तित करने की अनुमति है : रूपांतरण जो आप कर सकते हैं char ** से char * const * तक, या समकक्ष से "पॉइंटर से (सूचक से char)" पॉइंटर से (const पॉइंटर से char) "।

चूंकि मुझे लगता है कि एक निरंतर स्ट्रिंग को पार करने की तुलना में एक गैर-स्थिर स्ट्रिंग को पार करने की संभावना अधिक है, तो मैं const को पोस्ट करने के लिए आगे बढ़ूंगा - असंभव मामले के लिए गलत स्थिति सामान्य केस को एक कंपाइलर त्रुटि बनाने के लिए बेहतर है।

+4

लेकिन सी ++ आपको फ़ंक्शन को ओवरलोड करने से नहीं रोकता है: आपके पास 'long int strtol (char * nptr, char ** endptr, int base) हो सकता है; '* और *' long int strtol (const char * nptr, const char ** endptr, int base); ': यह आपकी संकलन त्रुटि को हल करता है। दरअसल, यह मानक ऐसे अन्य कार्यों के लिए करता है, जैसे 'strchr' और' strstr', – Thanatos

+0

आप सी अकसर किये गए सवाल वेब साइट का संदर्भ ले सकते हैं ['const char * p',' char const * p' के बीच क्या अंतर है, और 'char * const p'?] (http://c-faq.com/ansi/constptrconst.html) और, विशेष रूप से, [मैं एक समारोह में' char ** 'क्यों नहीं पारित कर सकता हूं जो' सी ++ एफएक्यू के बजाय कॉन्स char ** '?] (http://c-faq.com/ansi/constmismatch.html), हालांकि मुझे पूर्ण विश्वास नहीं है कि स्पष्टीकरण को समझना आसान है। –

1

पहले तर्क के लिए 'कॉन्स्ट char *' का अर्थ है कि strtol() स्ट्रिंग को संशोधित नहीं करेगा।

लौटे पॉइंटर के साथ आप क्या करते हैं वह आपका व्यवसाय है।

हां, इसे एक प्रकार के सुरक्षा उल्लंघन के रूप में माना जा सकता है; सी ++ शायद चीजों को अलग-अलग करेगा (हालांकि, जहां तक ​​मैं कह सकता हूं, आईएसओ/आईईसी 14882: 1 99 8 <cstdlib> को सी में समान हस्ताक्षर के साथ परिभाषित करता है)।

+0

सी ++ सी के समान हस्ताक्षर के साथ strtol (और cstdlib में सब कुछ) परिभाषित करता है, लेकिन cstring और cwchar में सब कुछ नहीं। –

6

हां, और अन्य कार्यों में एक ही "कॉन्स्ट-लॉंडरिंग" मुद्दा है (उदाहरण के लिए strchr, strstr, यह सब कुछ)।

ठीक लिए इस कारण से सी ++ भार के कहते हैं (21.4: 4): समारोह हस्ताक्षर strchr(const char*, int) दो घोषणाओं की जगह:

const char* strchr(const char* s, int c); 
     char* strchr(  char* s, int c); 

लेकिन सी में निश्चित रूप से आप दोनों स्थिरांक-सही संस्करण नहीं हो सकता उसी नाम से, इसलिए आपको कॉन्स्ट-गलत समझौता मिलता है।

सी ++ स्ट्रेटोल और स्ट्रेट के लिए समान ओवरलोड का उल्लेख नहीं करता है, और वास्तव में मेरे कंपाइलर (जीसीसी) में उनके पास नहीं है।मुझे नहीं पता क्यों नहीं: तथ्य यह है कि आप char** से const char** (ओवरलोडिंग की अनुपस्थिति के साथ) को स्पष्ट रूप से नहीं डाल सकते हैं, लेकिन मुझे यह नहीं पता कि सी ++ अधिभार के साथ क्या गलत होगा:

extern "C" { 
long int strtol(const char *nptr, const char **endptr, int base); 
long int strtol(char *nptr, char **endptr, int base); 
} 

जाहिर है इन दोनों को एक ही लिंक समय प्रतीक को हल:

long strtol(const char*, const char**, int); 
+1

स्ट्लपोर्ट इस अधिभार (और कुछ अन्य) प्रदान करता है। –

1

मैं एक संकलक, प्रदान करता है कि जब सी ++ मोड में संकलन है।

संपादित करें: सी ++ मानक के अनुसार, इस शीर्षलेख को संकलित नहीं करना चाहिए। मैं संकलक अनुमान लगा रहा हूं बस इसके लिए जांच नहीं की। वास्तव में परिभाषाएं सिस्टम हेडर फ़ाइलों में दिखाई देती हैं।

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