معالجة السلاسل النصية في لغة C

تحتوي لغة البرمجة C على مجموعة من الدوال لتنفيذ عمليات على السلاسل النصية (سلاسل الأحرف وسلاسل البايتات) في مكتبتها القياسية . وتدعم هذه الدوال عمليات متنوعة، مثل النسخ والدمج والتجزئة والبحث. بالنسبة لسلاسل الأحرف، تستخدم المكتبة القياسية اصطلاح إنهاء السلاسل بحرف فارغ : حيث تُمثَّل سلسلة مكونة من n حرفًا كمصفوفة من n + 1 عنصرًا، آخرها حرف فارغ ( NUL ) بقيمة عددية 0.

الدعم الوحيد للسلاسل النصية في لغة البرمجة نفسها هو أن المترجم يقوم بترجمة الثوابت النصية المقتبسة إلى سلاسل نصية منتهية بـ null.

التعريفات

تُعرَّف السلسلة بأنها تسلسل متصل من وحدات الترميز ينتهي بأول وحدة ترميز صفرية (تُسمى غالبًا وحدة الترميز NUL ). [ 1 ] وهذا يعني أن السلسلة لا يمكن أن تحتوي على وحدة الترميز الصفرية، لأن أول وحدة ترميز صفرية تُشير إلى نهاية السلسلة. طول السلسلة هو عدد وحدات الترميز التي تسبق وحدة الترميز الصفرية. [ 1 ] تكون الذاكرة التي تشغلها السلسلة دائمًا أكبر بوحدة ترميز واحدة من طولها، وذلك لأن هناك حاجة إلى مساحة لتخزين مُنهي السلسلة الصفري.

بشكل عام، يُشير مصطلح " سلسلة نصية " إلى سلسلة نصية تكون وحدة ترميزها من النوع char8 بت، وهو ما يُعادل 8 بتات بالضبط على جميع الأجهزة الحديثة. يُعرّف معيار C90 السلاسل النصية العريضة [ 1 ] التي تستخدم وحدة ترميز من النوع wchar_t16 أو 32 بت على الأجهزة الحديثة. كان هذا مُصمماً خصيصاً لـ Unicode، ولكن أصبح من الشائع بشكل متزايد استخدام UTF-8 في السلاسل النصية العادية لـ Unicode بدلاً من ذلك.

يتم تمرير السلاسل النصية إلى الدوال عن طريق تمرير مؤشر إلى وحدة التعليمات البرمجية الأولى. ولأن السلاسل النصية العريضة والسلاسل النصية العادية char*من wchar_t*نوعين مختلفين، فإن الدوال التي تعالج السلاسل النصية العريضة تختلف عن تلك التي تعالج السلاسل النصية العادية، ولها أسماء مختلفة.

"text"تُحوّل السلاسل النصية الحرفية ( في شفرة المصدر بلغة C) إلى مصفوفات ( char[]في لغة C أو const char[]C++) أثناء عملية الترجمة. [ 2 ] والنتيجة هي مصفوفة من وحدات الشفرة تحتوي على جميع الأحرف بالإضافة إلى وحدة شفرة صفرية في النهاية. في لغة C90، L"text"ينتج عن ذلك سلسلة نصية عريضة. يمكن أن تحتوي السلسلة النصية الحرفية على وحدة الشفرة الصفرية (إحدى الطرق هي إضافتها \0إلى شفرة المصدر)، ولكن هذا سيؤدي إلى انتهاء السلسلة عند تلك النقطة. سيتم وضع باقي السلسلة النصية الحرفية في الذاكرة (مع إضافة وحدة شفرة صفرية أخرى في النهاية)، ولكن من المستحيل معرفة ما إذا كانت وحدات الشفرة هذه قد تُرجمت من السلسلة النصية الحرفية، وبالتالي فإن شفرة المصدر هذه ليست سلسلة نصية حرفية. [ 3 ]

ترميز الأحرف

تنتهي كل سلسلة عند أول ظهور لوحدة الترميز الصفرية من النوع المناسب ( charأو wchar_t). بالتالي، char*يمكن أن تحتوي سلسلة البايتات ( ) على أحرف غير NUL في ASCII أو أي امتداد ASCII ، ولكن ليس على أحرف في ترميزات مثل UTF-16 (حتى لو كانت وحدة الترميز 16 بت غير صفرية، فقد يكون بايتها الأعلى أو الأدنى صفرًا). يتم تحديد الترميزات التي يمكن تخزينها في السلاسل العريضة من خلال عرض wchar_t. في معظم التطبيقات، wchar_tيكون عرض 16 بت على الأقل، وبالتالي يمكن تخزين جميع ترميزات 16 بت، مثل UCS-2 . إذا wchar_tكان عرض 32 بت، فيمكن تخزين ترميزات 32 بت، مثل UTF-32 . (يتطلب المعيار "نوعًا يحتوي على أي حرف عريض"، وهو ما لم يعد صحيحًا في نظام ويندوز منذ التحول من UCS-2 إلى UTF-16. وقد اعتُرف بهذا كعيب في المعيار وتم إصلاحه في لغة C++.) [ 4 ] أضافت لغتا C++11 و C11 نوعين بعرضين char16_tمحددين char32_t. [ 5 ]

يمكن استخدام ترميزات متغيرة العرض في كلٍ من السلاسل البايتية والسلاسل العريضة. يُقاس طول السلسلة ومواضعها بالبايتات wchar_t، وليس بالأحرف، مما قد يُربك المبرمجين المبتدئين. يُستخدم ترميز UTF-8 و Shift JIS غالبًا في سلاسل البايت في لغة C، بينما يُستخدم ترميز UTF-16wchar_t غالبًا في السلاسل العريضة عندما يكون طول السلسلة 16 بت. قد يؤدي اقتطاع السلاسل ذات الأحرف متغيرة العرض باستخدام دوال مثل `fl` strncpyإلى إنتاج تسلسلات غير صالحة في نهاية السلسلة. قد يكون هذا غير آمن إذا تم تفسير الأجزاء المقتطعة بواسطة كود يفترض صحة المدخلات.

يعتمد دعم القيم الحرفية لـ Unicode، مثل UTF-8 أو UTF-16 أو UTF-32 (حسب الترميز)، على التنفيذ [ 6 ] ، وقد يتطلب أن يكون كود المصدر بنفس الترميز، خاصةً في الحالات التي قد ينسخ فيها المترجم ما بين علامتي الاقتباس. تتطلب بعض المترجمات أو المحررات إدخال جميع الأحرف غير ASCII كسلاسل لكل بايت من UTF-8، و/أو لكل كلمة من UTF-16. منذ C11 (وC++11)، يتوفر بادئة حرفية جديدة تضمن استخدام UTF-8 لسلسلة بايت حرفية، كما في [ 7 ] . منذ C++20 و C23 ، أُضيف نوع مخصص لتخزين أحرف UTF-8، وتغيرت أنواع الأحرف والسلاسل الحرفية التي تبدأ بـ u8 إلى u8 و u8 على التوالي.charfoo[512]="φωωβαρ";wchar_tfoo[512]=L"φωωβαρ";wchar_tchar\xNN\uNNNNu8charfoo[512]=u8"φωωβαρ";char8_tchar8_tchar8_t[]

سمات

مصطلحات

في الوثائق التاريخية، كان يُستخدم مصطلح "حرف" غالبًا بدلًا من "بايت" لسلاسل لغة C، مما يدفع الكثيرين للاعتقاد بأن هذه الدوال لا تعمل مع ترميز UTF-8 . في الواقع، تُعرَّف جميع الأطوال بالبايت، وهذا صحيح في جميع التطبيقات، وتعمل هذه الدوال مع UTF-8 بنفس كفاءة عملها مع ترميزات البايت الواحد. تم تعديل وثائق BSD لتوضيح ذلك، لكن وثائق POSIX وLinux وWindows لا تزال تستخدم مصطلح "حرف" في مواضع كثيرة حيث يكون "بايت" أو "wchar_t" هو المصطلح الصحيح.

تستطيع الدوال المُخصصة لمعالجة مخازن الذاكرة معالجة سلاسل البايتات التي تتضمن بايتات فارغة كجزء من البيانات. تبدأ أسماء هذه الدوال عادةً بـ mem، عكس strالبادئة .

العناوين

تُصرَّح معظم الدوال التي تعمل على سلاسل C في string.hملف الرأس ( cstringفي C++)، بينما تُصرَّح الدوال التي تعمل على سلاسل C العريضة في wchar.hملف الرأس ( cwcharفي C++). تحتوي ملفات الرأس هذه أيضًا على تعريفات للدوال المستخدمة في معالجة مخازن الذاكرة؛ لذا فإن التسمية غير دقيقة إلى حد ما.

تُعدّ الدوال المُعلنة في مكتبة C القياسيةstring.h شائعة الاستخدام للغاية، إذ تضمن هذه المكتبة عملها على أي منصة تدعم لغة C. مع ذلك، توجد بعض المشكلات الأمنية المتعلقة بهذه الدوال، مثل احتمالية حدوث تجاوزات في المخزن المؤقت عند استخدامها بشكل غير دقيق، مما يدفع المبرمجين إلى تفضيل بدائل أكثر أمانًا، وإن كانت أقل قابلية للنقل، ومن بينها بعض الدوال الشائعة المذكورة أدناه. كما أن بعض هذه الدوال تُخالف مبدأ "const-correctness" بقبولها مؤشرًا نصيًا وإرجاعها قيمة غير مؤشرية داخل النص. ولتصحيح هذا، تم فصل بعضها إلى دالتين مُحمّلتين بشكل زائد في إصدار C++ من المكتبة القياسية.constconst

الثوابت والأنواع

اسمملحوظات
باطلتوسيع الماكرو إلى ثابت المؤشر الفارغ ؛ أي ثابت يمثل قيمة مؤشر مضمونة بأنها ليست عنوانًا صالحًا لكائن في الذاكرة.
wchar_tنوع البيانات المستخدم لوحدة الترميز في السلاسل النصية "العريضة". يشترط معيار لغة C أن يكون wchar_t عريضًا بما يكفي لاستيعاب أوسع مجموعة أحرف بين لغات النظام المدعومة [ 8 ] وأن يكون حجمه أكبر من أو يساوي حجم char [ 9 ] . في نظام التشغيل Windows ، وهو النظام الوحيد الذي يستخدم wchar_t على نطاق واسع، يُعرَّف بأنه 16 بت [ 10 وهو ما كان كافيًا لتمثيل أي حرف من أحرف Unicode ( UCS-2 )، ولكنه الآن يكفي فقط لتمثيل وحدة ترميز UTF-16 ، والتي قد تكون نصف نقطة ترميز. أما في الأنظمة الأخرى، فيُعرَّف بأنه 32 بت، وتتسع له دائمًا نقطة ترميز Unicode. هذا الاختلاف يجعل الشيفرة البرمجية التي تستخدم wchar_t غير قابلة للنقل.
wint_tنوع عدد صحيح يمكنه تخزين أي قيمة من نوع wchar_t بالإضافة إلى قيمة الماكرو WEOF. عادةً ما تكون قيمة موقعة 32 بت.
char8_t [ 11 ]يُعدّ جزءًا من معيار C منذ C23، في <uchar.h> ، وهو نوع مناسب لتخزين أحرف UTF-8. [ 12 ]
char16_t [ 13 ]يُعدّ نوع البيانات `wchar_t` جزءًا من معيار لغة C منذ الإصدار C11 ، [ 14 ] في الملف <uchar.h> ، وهو قادر على استيعاب 16 بت حتى لو كان حجم `wchar_t` مختلفًا. إذا تم تعريف الماكرو على أنه 1 ، فسيتم استخدام هذا النوع لترميز UTF-16 على ذلك النظام. هذا هو الحال دائمًا في الإصدار C23. [ 15 ] لا تُعرّف لغة C++ ماكرو مماثلًا، ولكن يتم استخدام هذا النوع دائمًا لترميز UTF-16 في تلك اللغة. [ 16 ]__STDC_UTF_16__
char32_t [ 13 ]يُعدّ نوع البيانات `wchar_t` جزءًا من معيار لغة C منذ الإصدار C11، [ 17 ] في الملف <uchar.h> ، وهو قادر على استيعاب 32 بت حتى لو كان حجم `wchar_t` مختلفًا. إذا تم تعريف الماكرو على أنه 1 ، فسيتم استخدام هذا النوع لترميز UTF-32 على ذلك النظام. هذا هو الحال دائمًا في الإصدار C23. [ 15 ] لا تُعرّف لغة C++ ماكرو مماثلًا، ولكن يتم استخدام هذا النوع دائمًا لترميز UTF-32 في تلك اللغة. [ 16 ]__STDC_UTF_32__
mbstate_tيحتوي على جميع المعلومات المتعلقة بحالة التحويل المطلوبة من استدعاء دالة إلى أخرى.

الوظائف

سلسلة بايتوتر عريضالوصف [ ملاحظة 1 ]
معالجة السلاسل النصيةstrcpy [ 18 ]wcscpy [ 19 ]ينسخ سلسلة نصية إلى أخرى
strncpy [ 20 ]wcsncpy [ 21 ]يكتب بالضبط n بايت، إما بنسخها من المصدر أو بإضافة قيم فارغة.
strcat [ 22 ]wcscat [ 23 ]يُلحق سلسلة نصية بسلسلة نصية أخرى
strncat [ 24 ]wcsncat [ 25 ]لا يُلحق أكثر من n بايت من سلسلة نصية إلى أخرى
strxfrm [ 26 ]wcsxfrm [ 27 ]يحوّل سلسلة نصية وفقًا للغة الحالية
فحص الأوتارstrlen [ 28 ]wcslen [ 29 ]يُعيد طول السلسلة
strcmp [ 30 ]wcscmp [ 31 ]يقارن بين سلسلتين نصيتين ( مقارنة ثلاثية )
strncmp [ 32 ]wcsncmp [ 33 ]يقارن عددًا محددًا من البايتات في سلسلتين نصيتين
strcoll [ 34 ]wcscoll [ 35 ]يقارن بين سلسلتين نصيتين وفقًا للغة الحالية
strchr [ 36 ]wcschr [ 37 ]يعثر على أول ظهور لبايت في سلسلة نصية
strrchr [ 38 ]wcsrchr [ 39 ]يعثر على آخر ظهور لبايت في سلسلة نصية
strspn [ 40 ]wcsspn [ 41 ]تُعيد هذه الدالة عدد البايتات الأولية في سلسلة نصية موجودة في سلسلة نصية ثانية.
strcspn [ 42 ]wcscspn [ 43 ]تُعيد هذه الدالة عدد البايتات الأولية في سلسلة نصية غير موجودة في سلسلة نصية ثانية.
strpbrk [ 44 ]wcspbrk [ 45 ]يعثر على أول ظهور لبايت في مجموعة ضمن سلسلة نصية
strstr [ 46 ]wcsstr [ 47 ]يجد أول ظهور لسلسلة فرعية في سلسلة نصية
strtok [ 48 ]wcstok [ 49 ]يقسم سلسلة نصية إلى رموز
متنوعstrerror [ 50 ]غير متوفريُعيد سلسلة نصية تحتوي على رسالة مُستمدة من رمز خطأ
التلاعب بالذاكرةmemset [ 51 ]wmemset [ 52 ]يملأ المخزن المؤقت ببايت مكرر. منذ الإصدار C23 ، تمت إضافة الدالة memset_explicit() لمسح البيانات الحساسة.
memcpy [ 53 ]wmemcpy [ 54 ]ينسخ مخزنًا مؤقتًا إلى آخر. منذ الإصدار C23 ، تمت إضافة الدالة memccpy() لدمج السلاسل النصية بكفاءة.
memmove [ 55 ]wmemmove [ 56 ]ينسخ مخزنًا مؤقتًا إلى آخر، وقد يتداخلان.
memcmp [ 57 ]wmemcmp [ 58 ]يقارن بين مخزنين مؤقتين (مقارنة ثلاثية)
memchr [ 59 ]wmemchr [ 60 ]يعثر على أول ظهور لبايت في المخزن المؤقت
  1. بالنسبة لوظائف السلاسل العريضة، استبدل wchar_t بـ "byte" في الوصف

وظائف متعددة البايت

اسموصف
mblen [ 61 ]يُعيد عدد البايتات في الحرف متعدد البايتات التالي
mbtowc [ 62 ]يحوّل الحرف متعدد البايت التالي إلى حرف عريض
wctomb [ 63 ]يحوّل الحرف العريض إلى تمثيله متعدد البايت
mbstowcs [ 64 ]يحوّل سلسلة نصية متعددة البايتات إلى سلسلة نصية عريضة
wcstombs [ 65 ]يحوّل سلسلة نصية عريضة إلى سلسلة نصية متعددة البايتات
btowc [ 66 ]يحوّل حرفًا أحادي البايت إلى حرف عريض، إن أمكن.
wctob [ 67 ]يحوّل الحرف العريض إلى حرف أحادي البايت، إن أمكن.
mbsinit [ 68 ]يتحقق مما إذا كان كائن الحالة يمثل الحالة الابتدائية
mbrlen [ 69 ]تُعيد هذه الدالة عدد البايتات في الحرف متعدد البايتات التالي، بناءً على الحالة المُعطاة.
mbrtowc [ 70 ]يحوّل الحرف متعدد البايتات التالي إلى حرف عريض، مع مراعاة الحالة.
wcrtomb [ 71 ]يحوّل الحرف العريض إلى تمثيله متعدد البايتات، مع مراعاة الحالة.
mbsrtowcs [ 72 ]يحوّل سلسلة نصية متعددة البايتات إلى سلسلة نصية عريضة، مع مراعاة الحالة.
wcsrtombs [ 73 ]يحوّل سلسلة نصية عريضة إلى سلسلة نصية متعددة البايتات، مع تحديد الحالة.
mbrtoc8 [ 74 ]يحوّل الحرف متعدد البايتات التالي إلى حرف UTF-8، مع تحديد الحالة.
c8rtomb [ 75 ]يحوّل نقطة ترميز واحدة من UTF-8 إلى تمثيل حرفي متعدد البايتات ضيق، مع إعطاء الحالة
mbrtoc16 [ 76 ]يحوّل الحرف متعدد البايتات التالي إلى حرف UTF-16، مع تحديد الحالة.
c16rtomb [ 77 ]يحوّل نقطة ترميز واحدة من UTF-16 إلى تمثيل حرفي متعدد البايتات ضيق، مع إعطاء الحالة
mbrtoc32 [ 78 ]يحوّل الحرف متعدد البايتات التالي إلى حرف UTF-32، مع تحديد الحالة.
c32rtomb [ 79 ]يحوّل نقطة ترميز واحدة من UTF-32 إلى تمثيل حرفي متعدد البايتات ضيق، مع إعطاء الحالة

جميع هذه الوظائف تحتاج إلىmbstate_tالكائن، الذي كان في الأصل موجودًا في الذاكرة الثابتة (مما جعل الدوال غير آمنة للاستخدام في بيئات متعددة الخيوط)، وفي الإضافات اللاحقة، يجب على المستدعي الاحتفاظ به. كان الهدف الأصلي من ذلك هو تتبع حالات الإزاحة فيمللا تحتاج الترميزات الحديثة مثل UTF-8 إلى ذلك. ومع ذلك، فقد صُممت هذه الوظائف على افتراض أنمرحاضالتشفير ليس تشفيرًا متغير العرض، وبالتالي فهو مصمم للتعامل مع عرض واحد فقط.wchar_tيتم تمريرها في كل مرة، عن طريق تمرير القيمة بدلاً من استخدام مؤشر سلسلة نصية. وبما أن UTF-16 هو ترميز ذو عرض متغير، فإنmbstate_tتمت إعادة استخدامها لتتبع أزواج البدائل في الترميز الواسع، على الرغم من أنه لا يزال يتعين على المتصل اكتشافها واستدعائها.mbtowcمرتين لحرف واحد. [ 80 ] [ 81 ] [ 82 ] وتقر الإضافات اللاحقة للمعيار بأن التحويل الوحيد الذي يهتم به المبرمجون هو بين UTF-8 وUTF-16، وتوفر ذلك بشكل مباشر.

التحويلات الرقمية

سلسلة بايتوتر عريضالوصف [ ملاحظة 1 ]
atof [ 83 ]غير متوفريحوّل سلسلة نصية إلى قيمة عددية عشرية ('atof' تعني 'تحويل ASCII إلى عدد عشري')
atoi atol atoll [ 84 ]غير متوفريحول سلسلة نصية إلى عدد صحيح ( C99 ) ('atoi' تعني 'تحويل ASCII إلى عدد صحيح')
strtof ( C99 ) [ 85 ] strtod [ 86 ] strtold ( C99 ) [ 87 ]wcstof ( C99 ) [ 88 ] wcstod [ 89 ] wcstold ( C99 ) [ 90 ]يحوّل سلسلة نصية إلى قيمة عددية عشرية
strtol strtoll [ 91 ]wcstol wcstoll [ 92 ]يحوّل سلسلة نصية إلى عدد صحيح مُوقّع
strtoul strtoull [ 93 ]wcstoul wcstoull [ 94 ]يحوّل سلسلة نصية إلى عدد صحيح غير مُوقّع
  1. هنا، تشير السلسلة إما إلى سلسلة بايت أو سلسلة عريضة

تحتوي مكتبة C القياسية على العديد من الدوال لتحويل الأرقام. تُعرَّف الدوال التي تتعامل مع سلاسل البايت في stdlib.hملف الرأس ( cstdlibheader في C++). تُعرَّف الدوال التي تتعامل مع السلاسل العريضة في wchar.hملف الرأس ( cwcharheader في C++).

الدوال strchrو bsearchو strpbrkو strrchrو strstrو memchrونظائرها الواسعة ليست صحيحة من حيث الثوابت ، لأنها تقبل constمؤشرًا لسلسلة نصية وتعيد قيمة غير constمؤشرية داخل السلسلة. وقد تم إصلاح هذا في C23 . [ 95 ]

كذلك، منذ التعديل المعياري الأول (C95)، atoxxتُعتبر الدوال مُضمنة في strtoxxxالدوال الأخرى، ولذلك لا يُوفر C95 ولا أي معيار لاحق نسخًا ذات أحرف واسعة لهذه الدوال. ويُعارض ذلك atoxxبأنها لا تُميز بين الخطأ و 0... [ 96 ]

قامت العديد من المعايير ذات الصلة بتوسيع وظائف معالجة السلاسل النصية التي يوفرها معيار لغة C، بما في ذلك BSD و SVID و POSIX . وقد أُضيفت بعض هذه الوظائف في معايير C الأحدث (مثل C11 و C23 ).

اسممصدروصف
bzero [ 97 ]4.2BSD، POSIX.1-2001يقوم بتصفير المخزن المؤقت. تم إيقاف هذه الخاصية بواسطة memset وإزالتها في معيار POSIX.1-2008.
memccpy [ 98 ]4.4BSD، SVID4، POSIX.1-2001، C23نسخ البيانات بين مخزنين مؤقتين غير متداخلين، والتوقف عند العثور على بايت معين.
mempcpy [ 99 ]جنونسخ بين مخزنين مؤقتين غير متداخلين، وإرجاع مؤشر إلى البايت الذي يلي البايت الأخير المكتوب.
strcasecmp , strncasecmp [ 100 ]4.4BSD، POSIX.1-2001إصدارات غير حساسة لحالة الأحرف من strcmp و strncmp على التوالي.
strcat_s , [ 101 ] strncat_s [ 102 ]ويندوز، C11إصدارات التحقق من الحدود من strcat و strncat على التوالي.
strcpy_s , [ 103 ] strncpy_s [ 104 ]ويندوز، C11إصدارات التحقق من الحدود من strcpy و strncpy على التوالي.
strdup , strndup [ 105 ]POSIX.1-2001، C23يقوم بتخصيص الذاكرة وتكرار سلسلة نصية فيها.
strerror_r [ 106 ]POSIX.1-2001، جنونسخة آمنة للاستخدام المتزامن من دالة strerror . نسخة GNU غير متوافقة مع نسخة POSIX.
strlcpy [ 107 ]POSIX.1-2024صيغة معدلة من دالة strcpy تقوم باقتطاع النتيجة لتناسب المخزن المؤقت الوجهة. [ 108 ]
strlcat [ 107 ]POSIX.1-2024صيغة معدلة من دالة strcat تقوم باقتطاع النتيجة لتناسب المخزن المؤقت الوجهة. [ 108 ]
strsignal [ 109 ]SVID3، POSIX.1-2008يُعيد تمثيلاً نصياً لرمز الإشارة .
strtok_r [ 110 ]POSIX.1-1996نسخة آمنة للاستخدام المتزامن من دالة strtok .

strlcpy، strlcat

على الرغم من الحاجة المُلحة لاستبدال strcat[ 22 ] و strcpy[ 18 ] بدوال لا تسمح بتجاوز سعة المخزن المؤقت، لم يظهر معيار مُعتمد. ويعود ذلك جزئيًا إلى اعتقاد خاطئ لدى العديد من مُبرمجي لغة C بأن الدالتين [108] و[18] strncatتُحققان strncpyالسلوك المطلوب؛ إلا أن أيًا منهما لم يُصمم لهذا الغرض (إذ صُممتا لمعالجة مخازن السلاسل النصية ذات الحجم الثابت والمُضافة إليها أصفار، وهو تنسيق بيانات أقل شيوعًا في البرامج الحديثة)، كما أن سلوكهما ومعاملاتهما غير بديهية، وغالبًا ما تُكتب بشكل خاطئ حتى من قِبل المُبرمجين الخبراء. [ 108 ]

أكثر البدائل شيوعًا هي الدالتان [ 111 ] strlcatو [ strlcpy112 ] ، اللتان ظهرتا في OpenBSD 2.4 في ديسمبر 1998. [ 108 ] تقوم هاتان الدالتان دائمًا بكتابة قيمة NUL واحدة إلى المخزن المؤقت الوجهة، مع اقتطاع النتيجة إذا لزم الأمر، وتعيدان حجم المخزن المؤقت المطلوب، مما يسمح باكتشاف الاقتطاع وتوفير حجم لإنشاء مخزن مؤقت جديد لا يتم اقتطاعه. لفترة طويلة، لم يتم تضمينهما في مكتبة GNU C (المستخدمة في البرامج على Linux)، وذلك استنادًا إلى ادعاءات بعدم كفاءتهما، [ 113 ] وتشجيع استخدام سلاسل C (بدلاً من شكل بديل أفضل للسلاسل النصية)، [ 114 ] [ 115 ] وإخفاء أخطاء محتملة أخرى. [ 116 ] [ 117 ] على الرغم من أن مكتبة glibc لم تُضِف دعمًا لها، فقد تمّ تنفيذ دالتي strlcat وstrlcpy في عدد من مكتبات C الأخرى، بما في ذلك مكتبات OpenBSD و FreeBSD و NetBSD و Solaris و OS X و QNX ، بالإضافة إلى مكتبات C بديلة لنظام Linux، مثل libbsd التي طُرحت عام 2008، [ 118 ] و musl التي طُرحت عام 2011، [ 119 ] [ 120 ] ، كما أُضيفت شفرة المصدر مباشرةً إلى مشاريع أخرى مثل SDL و GLib و ffmpeg و rsync ، وحتى داخليًا في نواة Linux . تغيّر هذا الوضع في عام 2024، حيث تشير الأسئلة الشائعة لمكتبة glibc إلى أنه اعتبارًا من الإصدار 2.38، تمّت إضافة الشفرة [ 121 ] وبالتالي إضافتها. [ 122 ] تم توحيد هذه الوظائف كجزء من POSIX.1-2024، [ 123 ] تتبع متتبع عيوب مجموعة أوستن ID 986 بعض المناقشات حول مثل هذه الخطط لـ POSIX.

كجزء من دورة تطوير الأمان لعام 2004 ، قدمت مايكروسوفت مجموعة من الدوال "الآمنة" ( strcpy_sإلى strcat_sجانب العديد من الدوال الأخرى). [ 124 ] تم توحيد هذه الدوال مع بعض التغييرات الطفيفة كجزء من معيار C11 الاختياري (الملحق K) الذي اقترحته ISO/IEC WDTR 24731. [ 125 ] تُجري هذه الدوال فحوصات متنوعة، بما في ذلك ما إذا كان طول السلسلة النصية يتجاوز سعة المخزن المؤقت. في حال فشل الفحوصات، يتم استدعاء دالة "معالج قيود وقت التشغيل" التي يحددها المستخدم، [ 126 ] والتي عادةً ما تُنهي البرنامج. [ 127 ] [ 128 ] لاقت هذه الدوال انتقادات واسعة لأنها طُبقت في البداية على نظام ويندوز فقط، وفي الوقت نفسه بدأت مايكروسوفت فيجوال سي++ بإصدار رسائل تحذيرية تقترح استخدام هذه الدوال بدلاً من الدوال القياسية. وقد تكهن البعض بأن هذا محاولة من مايكروسوفت لحصر المطورين في منصتها. [ 129 ] أظهرت التجربة مع هذه الدوال مشاكل كبيرة في اعتمادها وأخطاء في استخدامها، لذا اقتُرح حذف الملحق ك في المراجعة القادمة لمعيار لغة سي. [ 130 ] اقتُرح استخدام [ 131 ] [ 132 ]memset_s كوسيلة لتجنب تحسينات المُصرّف غير المرغوب فيها.

انظر أيضاً

ملحوظات

  1. على GitHub، هناك 7,813,206 استخدامًا لـstrlcpy، مقابل 38,644 استخدامًا لـstrcpy_s(و 15,286,150 استخدامًا لـstrcpy).

مراجع

  1. 1 2 3 "مسودة معيار C99 + TC3" (ملف PDF) . §7.1.1p1 . تم الاطلاع عليه بتاريخ 7 يناير 2011 .{{cite web}}: CS1 maint: location ( link )
  2. "مسودة معيار C99 + TC3" (ملف PDF) . §6.4.5p7 . تم الاطلاع عليه بتاريخ 7 يناير 2011 .{{cite web}}: CS1 maint: location ( link )
  3. "مسودة معيار C99 + TC3" (ملف PDF) . القسم 6.4.5، الحاشية 66. تم الاطلاع عليه بتاريخ 7 يناير 2011 .{{cite web}}: CS1 maint: location ( link )
  4. "تخفيف متطلبات wchar_t لتتوافق مع الممارسات الحالية" (PDF) .
  5. "الأنواع الأساسية" . en.cppreference.com .
  6. "مسودة معيار C99 + TC3" (ملف PDF) . §5.1.1.2 مراحل الترجمة ، ص1 . تم الاطلاع عليه بتاريخ 23 ديسمبر 2011 .{{cite web}}: CS1 maint: location ( link )
  7. "القيم النصية الحرفية" . en.cppreference.com . تم الاطلاع عليه بتاريخ 23 ديسمبر 2019 .
  8. "stddef.h - تعريفات الأنواع القياسية" . مجموعة Open Group . تم الاطلاع عليه بتاريخ 28 يناير 2017 .
  9. جيلام، ريتشارد (2003). تبسيط يونيكود: دليل عملي للمبرمجين حول معيار الترميز . أديسون-ويسلي بروفيشنال. ص 714. ISBN  9780201700527.
  10. "c++ - ما فائدة wchar_t في البرمجة العامة؟" . Stack Overflow . تم الاطلاع عليه في 1 أغسطس 2022 .
  11. "char, wchar_t, char8_t, char16_t, char32_t" . docs.microsoft.com . تم الاطلاع عليه في 1 أغسطس 2022 .
  12. "char8_t" .
  13. 1 2 " < cuchar > (uchar.h)" .
  14. "char16_t" .
  15. 1 2 "استبدال وحدات الماكرو النصية" .
  16. 1 2 "الأنواع الأساسية" .
  17. "char32_t" .
  18. 1 2 "strcpy - cppreference.com" . En.cppreference.com. 2 يناير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  19. "wcscpy - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  20. "strncpy - cppreference.com" . En.cppreference.com. 4 أكتوبر 2013. تم الاطلاع عليه في 6 مارس 2014 .
  21. "wcsncpy - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  22. 1 2 "strcat - cppreference.com" . En.cppreference.com. 8 أكتوبر 2013. تم الاطلاع عليه في 6 مارس 2014 .
  23. "wcscat - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  24. "strncat - cppreference.com" . En.cppreference.com. 1 يوليو 2013. تم الاطلاع عليه في 6 مارس 2014 .
  25. "wcsncat - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  26. "strxfrm - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  27. "wcsxfrm - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  28. "strlen - cppreference.com" . En.cppreference.com. 27 ديسمبر 2013. تم الاطلاع عليه في 6 مارس 2014 .
  29. "wcslen - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  30. "strcmp - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  31. "wcscmp - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  32. "strncmp - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  33. "wcsncmp - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  34. "strcoll - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  35. "wcscoll - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  36. "strchr - cppreference.com" . En.cppreference.com. 23 فبراير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  37. "wcschr - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  38. "strrchr - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  39. "wcsrchr - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  40. "strspn - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  41. "wcsspn - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  42. "strcspn - cppreference.com" . En.cppreference.com. 31 مايو 2013. تم الاطلاع عليه في 6 مارس 2014 .
  43. "wcscspn - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  44. "strpbrk - cppreference.com" . En.cppreference.com. 31 مايو 2013. تم الاطلاع عليه في 6 مارس 2014 .
  45. "wcspbrk - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  46. "strstr - cppreference.com" . En.cppreference.com. 16 أكتوبر 2013. تم الاطلاع عليه في 6 مارس 2014 .
  47. "wcsstr - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  48. "strtok - cppreference.com" . En.cppreference.com. 3 سبتمبر 2013. تم الاطلاع عليه في 6 مارس 2014 .
  49. "wcstok - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  50. "strerror - cppreference.com" . En.cppreference.com. 31 مايو 2013. تم الاطلاع عليه في 6 مارس 2014 .
  51. "memset - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  52. "wmemset - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  53. "memcpy - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  54. "wmemcpy - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  55. "memmove - cppreference.com" . En.cppreference.com. 25 يناير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  56. "wmemmove - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  57. "memcmp - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  58. "wmemcmp - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  59. "memchr - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  60. "wmemchr - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  61. "mblen - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  62. "mbtowc - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  63. "wctomb - cppreference.com" . En.cppreference.com. 4 فبراير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  64. "mbstowcs - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  65. "wcstombs - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  66. "btowc - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  67. "wctob - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  68. "mbsinit - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  69. "mbrlen - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  70. "mbrtowc - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  71. "wcrtomb - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  72. "mbsrtowcs - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  73. "wcsrtombs - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  74. ^ "mbrtoc8 – cppreference.com" . En.cppreference.com.
  75. "c8rtomb - cppreference.com" . En.cppreference.com.
  76. "mbrtoc16 - cppreference.com" . En.cppreference.com.
  77. ^ "c16rtomb - cppreference.com" . En.cppreference.com.
  78. "mbrtoc32 - cppreference.com" . En.cppreference.com.
  79. ^ "c23rtomb - cppreference.com" . En.cppreference.com.
  80. "6.3.2 تمثيل حالة التحويل" . مكتبة جنو سي . تم الاطلاع عليه بتاريخ 31 يناير 2017 .
  81. "root/src/multibyte/c16rtomb.c" . تم الاطلاع عليه بتاريخ 31 يناير 2017 .
  82. "محتويات /stable/11/lib/libc/locale/c16rtomb.c" . تم الاطلاع عليه بتاريخ 31 يناير 2017 .
  83. "atof - cppreference.com" . En.cppreference.com. 31 مايو 2013. تم الاطلاع عليه في 6 مارس 2014 .
  84. ^ "اتوي، أتول، جزيرة مرجانية - cppreference.com" . En.cppreference.com. 18 يناير 2014 . تم الاسترجاع 6 مارس 2014 .
  85. "strtof, strtod, strtold - cppreference.com" . En.cppreference.com. 4 فبراير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  86. "strtof, strtod, strtold - cppreference.com" . En.cppreference.com. 4 فبراير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  87. "strtof, strtod, strtold - cppreference.com" . En.cppreference.com. 4 فبراير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  88. "wcstof, wcstod, wcstold - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  89. "wcstof, wcstod, wcstold - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  90. "wcstof, wcstod, wcstold - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  91. "strtol, strtoll - cppreference.com" . En.cppreference.com. 4 فبراير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  92. "wcstol, wcstoll - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  93. "strtoul, strtoull - cppreference.com" . En.cppreference.com. 4 فبراير 2014. تم الاطلاع عليه في 6 مارس 2014 .
  94. "wcstoul, wcstoull - cppreference.com" . En.cppreference.com . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  95. "WG14-N3020 : وظائف المكتبة القياسية التي تحافظ على المحددات، الإصدار 4" (ملف PDF) . open-std.org . 13 يونيو 2022. 
  96. الأساس المنطقي C99، 7.20.1.1
  97. "bzero(3)" . OpenBSD . تم الاطلاع عليه بتاريخ 27 نوفمبر 2017 .
  98. "memccpy" . Pubs.opengroup.org . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  99. "mempcpy(3) - صفحة دليل لينكس" . Kernel.org . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  100. "strcasecmp(3) - صفحة دليل لينكس" . Kernel.org . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  101. "strcat_s, wcscat_s, _mbscat_s" . docs.microsoft.com . تم الاطلاع عليه بتاريخ 22 أبريل 2022 .
  102. "strncat_s, _strncat_s_l, wcsncat_s, _wcsncat_s_l, _mbsncat_s, _mbsncat_s_l" . docs.microsoft.com . تم الاطلاع عليه بتاريخ 9 ديسمبر 2025 .
  103. "strcpy_s, wcscpy_s, _mbscpy_s, _mbscpy_s_l" . docs.microsoft.com . تم الاطلاع عليه بتاريخ 22 أبريل 2022 .
  104. "strncpy_s, _strncpy_s_l, wcsncpy_s, _wcsncpy_s_l, _mbsncpy_s, _mbsncpy_s_l, _tcsncpy_s, _tcsncpy_s_l, _tcsnccpy_s, _tcsnccpy_s_l" . docs.microsoft.com . تم الاطلاع عليه بتاريخ 9 ديسمبر 2025 .
  105. "strdup" . Pubs.opengroup.org . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  106. "strerror(3) - صفحة دليل لينكس" . man7.org . تم الاطلاع عليه بتاريخ 3 نوفمبر 2019 .
  107. 1 2 "strlcpy، strlcat — نسخ ودمج السلاسل النصية ذات الحجم المحدود" . OpenBSD . تم الاطلاع عليه بتاريخ 26 مايو 2016 .
  108. 1 2 3 4 تود سي. ميلر؛ ثيو دي رادت (1999). "strlcpy و strlcat - نسخ ودمج السلاسل النصية بشكل متسق وآمن" . مؤتمر USENIX '99.
  109. "strsignal" . Pubs.opengroup.org . تم الاطلاع عليه بتاريخ 6 مارس 2014 .
  110. ^ "سترتوك" . Pubs.opengroup.org . تم الاسترجاع 6 مارس 2014 .
  111. تود سي. ميلر. "strlcpy.c" . مرجع BSD المتقاطع .
  112. تود سي. ميلر. "strlcat.c" . مرجع BSD المتقاطع .
  113. ميلر، داميان (أكتوبر 2005). "قابلية النقل الآمنة" ( ملف PDF) . تم الاطلاع عليه بتاريخ 26 يونيو 2016. تم اعتماد واجهة برمجة التطبيقات [strlcpy وstrlcat] هذه من قبل معظم أنظمة التشغيل الحديثة والعديد من حزم البرامج المستقلة [...]. الاستثناء الملحوظ هو مكتبة GNU القياسية للغة C، glibc، التي يرفض القائم على صيانتها بشدة تضمين واجهات برمجة التطبيقات المحسّنة هذه، واصفًا إياها بأنها "هراء BSD غير فعال بشكل فظيع"، على الرغم من وجود أدلة سابقة على أنها أسرع في معظم الحالات من واجهات برمجة التطبيقات التي تحل محلها.
  114. قائمة بريد libc-alpha مؤرشفة في 9 يونيو 2007 على موقع Wayback Machine ، رسائل مختارة من سلسلة 8 أغسطس 2000: 53 ، 60 ، 61
  115. إيجابيات وسلبيات دالة strlcpy(); LWN.net
  116. "إضافة strlcpy() إلى glibc" . lwn.net . تعني معالجة السلاسل النصية بشكل صحيح أنك تعرف دائمًا طول السلاسل النصية، وبالتالي يمكنك استخدام memcpy (بدلاً من strcpy).
  117. دليل وظائف مكتبة لينكس من ManKier.com "مع ذلك، قد يتساءل المرء عن مدى صحة هذه التحسينات، لأنها تُفقد الغرض الأساسي من الدالتين strlcpy() و strlcat(). في الواقع، كان الإصدار الأول من هذه الصفحة من الدليل خاطئًا."strlcpy(3)  
  118. "libbsd" . تم الاطلاع عليه بتاريخ 21 نوفمبر 2022 .
  119. "root/src/string/strlcpy.c" . تم الاطلاع عليه بتاريخ 28 يناير 2017 .
  120. "root/src/string/strlcat.c" . تم الاطلاع عليه بتاريخ 28 يناير 2017 .
  121. strlc{py|at} commit
  122. مناقشة حول دالتي strlcpy و strlcat في مكتبة glibc 2.38 على موقع Hacker News
  123. "strlcat" . Pubs.opengroup.org . تم الاطلاع عليه في 5 سبتمبر 2024 .
  124. لوفيل، مارتن. "صد الهجمات على التعليمات البرمجية الخاصة بك باستخدام مكتبات C و C++ الآمنة في Visual Studio 2005" . تم الاطلاع عليه بتاريخ 13 فبراير 2015 .
  125. مكتبة Safe C. "توفر مكتبة Safe C وظائف فحص حدود الذاكرة والسلاسل النصية وفقًا لمعيار ISO/IEC TR24731" . Sourceforge . تاريخ الاسترجاع: 6 مارس 2013 .
  126. "مسودة معيار C11" (ملف PDF) . §K.3.1.4p2 . تم الاطلاع عليه بتاريخ 13 فبراير 2013 .{{cite web}}: CS1 maint: location ( link )
  127. "مسودة معيار C11" (ملف PDF) . §K.3.6.1.1p4 . تم الاطلاع عليه بتاريخ 13 فبراير 2013 .{{cite web}}: CS1 maint: location ( link )
  128. "التحقق من صحة المعلمات" . 21 أكتوبر 2022.
  129. داني كاليف. "لقد عادوا إلى فعلتهم مجدداً" . إنفورم آي تي. مؤرشف من الأصل في 15 يناير 2012. تم الاطلاع عليه في 10 نوفمبر 2011 .
  130. "التجربة الميدانية مع الملحق ك - واجهات التحقق من الحدود" . تم الاطلاع عليه في 5 نوفمبر 2015 .
  131. "MSC06-C. احذر من تحسينات المُصرّف" . معيار ترميز لغة C الصادر عن SEI CERT .
  132. دليل وظائف مكتبة FreeBSDmemset_s(3)