Swift — सिस्टम प्रोग्रामिंग का अप्रत्याशित नायक
\n\nजब आप "सिस्टम प्रोग्रामिंग" सुनते हैं, तो आमतौर पर कठोर C, असेंबली या कम से कम Rust दिमाग में आता है। Swift? वही भाषा जो सुंदर मोबाइल ऐप के लिए है? पता चला, हाँ। और यह कोई मज़ाक नहीं है।
\n\nApple ने Swift में न केवल सुविधा और सुरक्षा दी है, बल्कि मेमोरी, पॉइंटर्स और सिस्टम कॉल पर पूर्ण नियंत्रण भी दिया है। इस लेख में, हम देखेंगे कि कैसे Swift यूटिलिटी, ड्राइवर, नेटवर्क डेमॉन और यहां तक कि ऑपरेटिंग सिस्टम के घटकों को लिखने के लिए आपका मुख्य उपकरण बन सकता है। आश्चर्यचकित होने के लिए तैयार रहें — कोड वास्तविक, काम करने वाला और बहुत दिलचस्प होगा।
\n\nSwift क्यों? सिस्टम प्रोग्रामिंग के तीन स्तंभ
\n\nसिस्टम प्रोग्रामिंग के लिए तीन चीजों की आवश्यकता होती है: प्रदर्शन, संसाधनों पर नियंत्रण और "हार्डवेयर के करीब" काम करने की क्षमता। Swift यह सब देता है, साथ ही कुछ अतिरिक्त भी।
\n\n- \n
- C के स्तर का प्रदर्शन। LLVM कंपाइलर कोड को C या C++ से कम नहीं ऑप्टिमाइज़ करता है। बेंचमार्क में, Swift अक्सर IO कार्यों में Go और Rust से आगे निकल जाता है। \n
- मेमोरी तक सीधी पहुंच। UnsafePointer, UnsafeMutablePointer तंत्र और रॉ बाइट्स के साथ काम करने के माध्यम से। \n
- समृद्ध मानक पुस्तकालय। अपने साथ ढेर सारी निर्भरताएं ले जाने की आवश्यकता नहीं है — सॉकेट, फ़ाइलों, प्रक्रियाओं के साथ काम करने के लिए सब कुछ पहले से मौजूद है। \n
साथ ही, Swift सुरक्षित बना हुआ है: यदि आप unsafe ब्लॉक का उपयोग नहीं करते हैं, तो कंपाइलर आपको बफर ओवरफ्लो और हैंगिंग पॉइंटर्स से बचाएगा। और जब आवश्यकता हो — बस withUnsafePointer लिखें और पूर्ण नियंत्रण प्राप्त करें।
मेमोरी के साथ काम: बाइट्स से स्ट्रक्चर तक
\n\nआइए मूल बातों से शुरू करें — रॉ मेमोरी के साथ काम करना। कल्पना करें कि आपको एक बाइनरी फ़ाइल पढ़नी है और इसे स्ट्रक्चर की एक सरणी के रूप में व्याख्या करना है। C में, आप malloc और sizeof के साथ संघर्ष करेंगे। Swift में — सुरुचिपूर्ण और सुरक्षित।
\n\nSwift में बाइनरी फ़ाइल पढ़ना
\n\nimport Foundation\n\nstruct Header {\n let magic: UInt32\n let version: UInt16\n let count: UInt16\n}\n\nfunc readBinaryFile(path: String) -> Header? {\n let data = try? Data(contentsOf: URL(fileURLWithPath: path))\n guard let data = data else { return nil }\n \n return data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in\n guard let baseAddress = ptr.baseAddress else { return nil }\n let headerPtr = baseAddress.assumingMemoryBound(to: Header.self)\n return headerPtr.pointee\n }\n}\n\nध्यान दें: हम मैन्युअल रूप से मेमोरी आवंटित नहीं कर रहे हैं। withUnsafeBytes एक अस्थायी पॉइंटर प्रदान करता है जो केवल क्लोजर के अंदर रहता है। यह सुरक्षित, कुशल है और अच्छे गद्य की तरह पढ़ा जाता है।
स्ट्रक्चर बनाना और पॉइंटर्स के साथ काम करना
\n\nक्या होगा यदि आपको मेमोरी में एक स्ट्रक्चर बनाना है और उसका पता सिस्टम कॉल को देना है? आसान!
\n\nstruct sockaddr_in {\n var sin_len: UInt8 = 0\n var sin_family: UInt8 = UInt8(AF_INET)\n var sin_port: in_port_t = 0\n var sin_addr: in_addr = in_addr(s_addr: 0)\n var sin_zero: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (0,0,0,0,0,0,0,0)\n}\n\nvar address = sockaddr_in()\naddress.sin_port = CFSwapInt16HostToBig(8080)\naddress.sin_addr.s_addr = inet_addr("127.0.0.1")\n\nlet ptr = withUnsafePointer(to: &address) { $0 }\nlet rawPtr = UnsafeRawPointer(ptr)\n\nयह कोड निम्न स्तर पर सॉकेट के साथ काम करने का आधार है। हम मैन्युअल रूप से स्ट्रक्चर को परिभाषित करते हैं, फ़ील्ड भरते हैं और connect या bind में पास करने के लिए एक रॉ पॉइंटर प्राप्त करते हैं।
सिस्टम कॉल और POSIX API
\n\nSwift POSIX के साथ बहुत अच्छी तरह से काम करता है। आप open, read, write, fork, exec कॉल कर सकते हैं — बिल्कुल पुराने अच्छे दिनों की तरह, लेकिन 21वीं सदी के सिंटैक्स के साथ।
Swift में fork + exec बनाना
\n\nimport Darwin\n\nfunc spawnProcess(path: String, args: [Str