Scroll to navigation

printf(3) Library Functions Manual printf(3)

الاسم

printf, fprintf, dprintf, sprintf, snprintf, vprintf, vfprintf, vdprintf, vsprintf, vsnprintf - تحويل المخرجات المنسقة

المكتبة

مكتبة سي المعيارية (libc، -lc)

موجز

#include <stdio.h>
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict stream,
            const char *restrict format, ...);
int dprintf(int fd,
            const char *restrict format, ...);
int sprintf(char *restrict str,
            const char *restrict format, ...);
int snprintf(char str[restrict .size], size_t size,
            const char *restrict format, ...);
int vprintf(const char *restrict format, va_list ap);
int vfprintf(FILE *restrict stream,
            const char *restrict format, va_list ap);
int vdprintf(int fd,
            const char *restrict format, va_list ap);
int vsprintf(char *restrict str,
            const char *restrict format, va_list ap);
int vsnprintf(char str[restrict .size], size_t size,
            const char *restrict format, va_list ap);

متطلبات ماكروات اختبار الميزات لـ glibc (انظر feature_test_macros(7)):

snprintf(), vsnprintf():


_XOPEN_SOURCE >= 500 || _ISOC99_SOURCE
|| /* glibc <= 2.19: */ _BSD_SOURCE

dprintf()، vdprintf():


منذ glibc 2.10:
_POSIX_C_SOURCE >= 200809L
قبل glibc 2.10:
_GNU_SOURCE

الوصف

تنتج الدوال في عائلة printf() مخرجات وفقاً لتنسيق format كما هو موضح أدناه. تكتب الدالتان printf() وvprintf() المخرجات إلى stdout، وهو دفق المخرجات القياسي؛ وتكتب fprintf() وvfprintf() المخرجات إلى دفق المخرجات stream المعطى؛ وتكتب sprintf() وsnprintf() وvsprintf() وvsnprintf() إلى السلسلة المحرفية str.

الدالة dprintf() هي نفسها fprintf() باستثناء أنها تخرج إلى واصف ملف، fd، بدلاً من دفق stdio(3).

تكتب الدالتان snprintf() وvsnprintf() على الأكثر size بايت (بما في ذلك بايت الخلو المنتهي ('\0')) إلى str.

الدوال vprintf() وvfprintf() وvdprintf() وvsprintf() وvsnprintf() تكافئ الدوال printf() وfprintf() وdprintf() وsprintf() وsnprintf() على التوالي، باستثناء أنها تُستدعى باستخدام va_list بدلاً من عدد متغير من المعطيات. لا تستدعي هذه الدوال ماكرو va_end. ولأنها تستدعي ماكرو va_arg، فإن قيمة ap تكون غير محددة بعد الاستدعاء. انظر stdarg(3).

تكتب كل هذه الدوال المخرجات تحت تحكم سلسلة format تحدد كيفية تحويل المعاملات اللاحقة (أو المعاملات التي تم الوصول إليها عبر مرافق المعاملات متغيرة الطول في stdarg(3)) للمخرجات.

تحدد معايير C99 وPOSIX.1-2001 أن النتائج تكون غير محددة إذا تسبب استدعاء sprintf() أو snprintf() أو vsprintf() أو vsnprintf() في حدوث نسخ بين كائنات متداخلة (على سبيل المثال، إذا كانت مصفوفة السلسلة المستهدفة وأحد معطيات المدخلات المقدمة يشيران إلى نفس الخبيئة). انظر التنبيهات CAVEATS.

تنسيق سلسلة التنسيق

سلسلة التنسيق هي سلسلة محارف، تبدأ وتنتهي في حالة الإزاحة المبدئية، إن وجدت. تتكون سلسلة التنسيق من صفر أو أكثر من التوجيهات: محارف عادية (ليست %)، والتي تُنسخ دون تغيير إلى دفق المخرجات؛ ومواصفات التحويل، والتي ينتج عن كل منها جلب صفر أو أكثر من المعاملات اللاحقة. تبدأ كل مواصفة تحويل بالمحرف %، وتنتهي بـ conversion specifier. وفيما بينهما قد يوجد (بهذا الترتيب) صفر أو أكثر من flags، و field width أدنى اختياري، و precision اختيارية و length modifier اختياري.

الصيغة العامة لمواصفة التحويل هي:


%[$][flags][width][.precision][length modifier]تحويل

يجب أن تتوافق المعاملات بشكل صحيح (بعد ترقية النوع) مع محدد التحويل. مبدئيًا، تُستخدم المعاملات بالترتيب المعطى، حيث يطلب كل '*' (انظر عرض الحقل و الدقة أدناه) وكل محدد تحويل المعامل التالي (ويعد خطأً إذا تم إعطاء عدد غير كافٍ من المعاملات). يمكن للمرء أيضًا تحديد المعامل الذي سيؤخذ صراحةً، في كل مكان يتطلب معاملًا، عن طريق كتابة "%m$" بدلاً من '%' و "*m$" بدلاً من '*'، حيث يشير العدد الصحيح العشري m إلى موضع المعامل المطلوب في قائمة المعاملات، مفهرسًا بدءًا من 1. وبالتالي،


printf("%*d", width, num);

و


printf("%2$*1$d", width, num);

متكافئان. يسمح النمط الثاني بالإشارات المتكررة لنفس المعامل. لا يتضمن معيار C99 النمط الذي يستخدم '$'، والذي يأتي من مواصفة UNIX الموحدة (Single UNIX Specification). إذا وُظف النمط الذي يستخدم '$'، فيجب استخدامه في جميع التحويلات التي تأخذ معاملًا وجميع معاملات العرض والدقة، ولكن يمكن خلطه مع تنسيقات "%%" التي لا تستهلك معاملًا. يجب ألا تكون هناك فجوات في أرقام المعاملات المحددة باستخدام '$'؛ على سبيل المثال، إذا حُدد المعاملان 1 و 3، فيجب أيضًا تحديد المعامل 2 في مكان ما في سلسلة التنسيق.

بالنسبة لبعض التحويلات الرقمية، يُستخدم محرف أساس ("الفاصلة العشرية") أو محرف تجميع الآلاف. يعتمد المحرف الفعلي المستخدم على جزء LC_NUMERIC من المحلية. (انظر setlocale(3).) تستخدم المحلية POSIX الرمز '.' كمحرف أساس، وليس لديها محرف تجميع. وبالتالي،


printf("%'.2f", 1234567.89);

ينتج عنها "1234567.89" في محلية POSIX، و "1234567,89" في محلية nl_NL، و "1.234.567,89" في محلية da_DK.

محارف الأعلام

يتبع المحرف % صفر أو أكثر من الأعلام التالية:

#
يجب تحويل القيمة إلى "شكل بديل". لتحويلات o، يُجعل المحرف الأول من سلسلة المخرجات صفرًا (عن طريق بادئة 0 إذا لم يكن صفرًا بالفعل). لتحويلات x و X، تسبق النتيجة غير الصفرية السلسلة "0x" (أو "0X" لتحويلات X). لتحويلات a، A، e، E، f، F، g، و G، ستحتوي النتيجة دائمًا على فاصلة عشرية، حتى لو لم تتبعها أرقام (عادةً ما تظهر الفاصلة العشرية في نتائج تلك التحويلات فقط إذا تبعها رقم). لتحويلات g و G، لا تُحذف الأصفار اللاحقة من النتيجة كما هو الحال بخلاف ذلك. بالنسبة لـ m، إذا كان errno يحتوي على رمز خطأ صالح، تُطبع مخرجات strerrorname_np(errno)؛ وخلاف ذلك، تُطبع القيمة المخزنة في errno كعدد عشري. بالنسبة للتحويلات الأخرى، تكون النتيجة غير محددة.
0
يجب حشو القيمة بالأصفار. لتحويلات d، i، o، u، x، X، a، A، e، E، f، F، g، و G، تُحشى القيمة المحولة من اليسار بالأصفار بدلاً من الفراغات. إذا ظهر العلمان 0 و - معًا، يُتجاهل العلم 0. إذا أُعطيت دقة مع تحويل عدد صحيح (d، i، o، u، x، و X)، يُتجاهل العلم 0. بالنسبة للتحويلات الأخرى، السلوك غير محدد.
-
يجب محاذاة القيمة المحولة لليسار على حدود الحقل. (المبدئي هو المحاذاة لليمين). تُحشى القيمة المحولة من اليمين بالفراغات، بدلاً من حشوها من اليسار بالفراغات أو الأصفار. يتخطى العلم - العلم 0 إذا أُعطيا معًا.
' '
(مسافة) يجب ترك فراغ قبل الرقم الموجب (أو السلسلة الفارغة) الناتج عن تحويل ذو إشارة.
+
يجب دائمًا وضع إشارة (+ أو -) قبل الرقم الناتج عن تحويل ذو إشارة. مبدئيًا، تُستخدم الإشارة للأرقام السالبة فقط. يتخطى العلم + المسافة إذا استخدما معًا.

أعلام المحارف الخمسة أعلاه معرفة في معيار C99. وتحدد مواصفة UNIX الموحدة علم محرف إضافي.

'
للتحويل العشري (i، d، u، f، F، g، G)، تُجمع المخرجات باستخدام محارف تجميع الآلاف إذا كانت معلومات المحلية تشير إلى ذلك. (انظر setlocale(3).) لاحظ أن العديد من إصدارات gcc(1) لا يمكنها تحليل هذا الخيار وستصدر تحذيراً. (لم يتضمن SUSv2 الخيار %'F، ولكن أضافه SUSv3.) لاحظ أيضاً أن المحلية المبدئية لبرنامج C هي "C" التي لا تشير معلوماتها إلى أي محرف لتجميع الآلاف. لذلك، دون استدعاء مسبق للدالة setlocale(3)، لن تُطبع أي محارف لتجميع الآلاف.

تضيف glibc 2.2 علم محرف إضافي.

لتحويل الأعداد الصحيحة العشرية (i، d، u) تستخدم المخرجات أرقام المخرجات البديلة للمحلية، إن وجدت. على سبيل المثال، منذ glibc 2.2.3، سيعطي هذا الأرقام العربية الهندية في المحلية الفارسية ("fa_IR").

عرض الحقل

سلسلة أرقام عشرية اختيارية (مع رقم أول غير صفري) تحدد الحد الأدنى لعرض الحقل. إذا كانت القيمة المحولة تحتوي على محارف أقل من عرض الحقل، فسيُحشى بالمسافات على اليسار (أو اليمين، إذا أُعطي علم الضبط لليسار). بدلاً من سلسلة الأرقام العشرية، يمكن كتابة "*" أو "*m$" (لعدد صحيح عشري m) لتحديد أن عرض الحقل مُعطى في المعطى التالي، أو في المعطى رقم m، على التوالي، والذي يجب أن يكون من نوع int. يُعامل عرض الحقل السالب كعلم '-' متبوعاً بعرض حقل موجب. لا يتسبب عدم وجود عرض حقل أو صغره في بتر الحقل بأي حال من الأحوال؛ إذا كانت نتيجة التحويل أعرض من عرض الحقل، فسيُوسع الحقل لاحتواء نتيجة التحويل.

الدقة

دقة اختيارية، على شكل نقطة ('.') متبوعة بسلسلة أرقام عشرية اختيارية. بدلاً من سلسلة الأرقام العشرية، يمكن كتابة "*" أو "*m$" (لعدد صحيح عشري m) لتحديد أن الدقة مُعطاة في المعطى التالي، أو في المعطى رقم m، على التوالي، والذي يجب أن يكون من نوع int. إذا أُعطيت الدقة كمجرد نقطة '.'، تُعتبر الدقة صفراً. تُعامل الدقة السالبة كما لو كانت الدقة محذوفة. يحدد هذا الحد الأدنى لعدد الأرقام التي ستظهر لتحويلات d وi وo وu وx وX، وعدد الأرقام التي ستظهر بعد محرف الفاصلة لتحويلات a وA وe وE وf وF، والحد الأقصى لعدد الأرقام المعنوية لتحويلات g وG، أو الحد الأقصى لعدد المحارف التي ستُطبع من سلسلة نصية لتحويلات s وS.

معدل الطول

هنا، يرمز "تحويل عدد صحيح" إلى تحويل d، i، o، u، x، أو X.

يتوافق تحويل عدد صحيح لاحق مع معامل signed char أو unsigned char، أو يتوافق تحويل n لاحق مع مؤشر إلى معامل signed char.
يتوافق تحويل عدد صحيح لاحق مع معامل short أو unsigned short، أو يتوافق تحويل n لاحق مع مؤشر إلى معامل short.
(ell) يتوافق تحويل عدد صحيح لاحق مع معامل long أو unsigned long، أو يتوافق تحويل n لاحق مع مؤشر إلى معامل long، أو يتوافق تحويل c لاحق مع معامل wint_t، أو يتوافق تحويل s لاحق مع مؤشر إلى معامل wchar_t. في تحويل a، A، e، E، f، F، g، أو G لاحق، يُتجاهل معدل الطول هذا (C99؛ ليس في SUSv2).
(ell-ell). يتوافق تحويل عدد صحيح لاحق مع معامل long long أو unsigned long long، أو يتوافق تحويل n لاحق مع مؤشر إلى معامل long long.
مرادف لـ ll. هذا امتداد غير معيار، مشتق من BSD؛ تجنب استخدامه في الكود الجديد.
يتوافق تحويل a، A، e، E، f، F، g، أو G لاحق مع معامل long double. (يسمح C99 بـ %LF، لكن SUSv2 لا يسمح بذلك).
يتوافق تحويل عدد صحيح لاحق مع معامل intmax_t أو uintmax_t، أو يتوافق تحويل n لاحق مع مؤشر إلى معامل intmax_t.
يتوافق تحويل عدد صحيح لاحق مع معامل size_t أو ssize_t، أو يتوافق تحويل n لاحق مع مؤشر إلى معامل size_t.
مرادف غير معيار لـ z يسبق ظهور z. لا تستخدمه في الكود الجديد.
يتوافق تحويل عدد صحيح لاحق مع معامل ptrdiff_t، أو يتوافق تحويل n لاحق مع مؤشر إلى معامل ptrdiff_t.

تحدد SUSv3 كل ما سبق، باستثناء تلك المعدلات المذكورة صراحةً كإضافات غير معيارية. حددت SUSv2 فقط معدلات الطول h (في hd، hi، ho، hx، hX، hn) و l (في ld، li، lo، lx، lX، ln، lc، ls) و L (في Le، LE، Lf، Lg، LG).

كامتداد غير معيار، تعامل تطبيقات GNU كلاً من ll و L كمرادفات، بحيث يمكن للمرء، على سبيل المثال، كتابة llg (كمرادف لـ Lg المتوافق مع المعايير) و Ld (كمرادف لـ lld المتوافق مع المعايير). هذا الاستخدام غير محمول.

محددات التحويل

محرف يحدد نوع التحويل المراد تطبيقه. محددات التحويل ومعانيها هي:

يُحول معامل int إلى تدوين عشري ذو إشارة. تعطي الدقة، إن وجدت، الحد الأدنى لعدد الأرقام التي يجب أن تظهر؛ إذا كانت القيمة المحولة تتطلب أرقامًا أقل، تُحشى من اليسار بالأصفار. الدقة المبدئية هي 1. عندما يُطبع 0 بدقة صريحة 0، تكون المخرجات فارغة.
يُحول معامل unsigned int إلى تدوين ثماني بدون إشارة (o)، أو عشري بدون إشارة (u)، أو سداسي عشري بدون إشارة (x و X). تُستخدم الأحرف abcdef لتحويلات x؛ بينما تُستخدم الأحرف ABCDEF لتحويلات X. تعطي الدقة، إن وجدت، الحد الأدنى لعدد الأرقام التي يجب أن تظهر؛ إذا كانت القيمة المحولة تتطلب أرقامًا أقل، تُحشى من اليسار بالأصفار. الدقة المبدئية هي 1. عندما يُطبع 0 بدقة صريحة 0، تكون المخرجات فارغة.
يُقرب معامل double ويُحول بالأسلوب [-]d.ddde±dd حيث يوجد رقم واحد (وهو غير صفري إذا كان المعامل غير صفري) قبل محرف الفاصلة العشرية، وعدد الأرقام بعدها يساوي الدقة؛ إذا كانت الدقة مفقودة، تُعتبر 6؛ إذا كانت الدقة صفرًا، فلا يظهر محرف فاصلة عشرية. يستخدم تحويل E الحرف E (بدلاً من e) لتقديم الأس. يحتوي الأس دائمًا على رقمين على الأقل؛ إذا كانت القيمة صفرًا، فإن الأس هو 00.
يُقرب معامل double ويُحول إلى تدوين عشري بالأسلوب [-]ddd.ddd، حيث يكون عدد الأرقام بعد محرف الفاصلة العشرية مساويًا لمواصفة الدقة. إذا كانت الدقة مفقودة، تُعتبر 6؛ إذا كانت الدقة صفرًا صراحةً، فلا يظهر محرف فاصلة عشرية. إذا ظهرت فاصلة عشرية، فيظهر رقم واحد على الأقل قبلها.
(لا تعرف SUSv2 عن F وتقول إنه يمكن توفير تمثيلات سلاسل محارف للانهاية و NaN. تضيف SUSv3 مواصفة لـ F. يحدد معيار C99 "[-]inf" أو "[-]infinity" للانهاية، وسلسلة تبدأ بـ "nan" لـ NaN، في حالة تحويل f، و "[-]INF" أو "[-]INFINITY" أو "NAN" في حالة تحويل F).
يُحول معامل double بالأسلوب f أو e (أو F أو E لتحويلات G). تحدد الدقة عدد الأرقام المعنوية. إذا كانت الدقة مفقودة، يتم إعطاء 6 أرقام؛ إذا كانت الدقة صفرًا، تُعامل كـ 1. يُستخدم الأسلوب e إذا كان الأس من تحويله أقل من -4 أو أكبر من أو يساوي الدقة. تُحذف الأصفار اللاحقة من الجزء الكسري من النتيجة؛ وتظهر الفاصلة العشرية فقط إذا تبعها رقم واحد على الأقل.
(C99؛ ليس في SUSv2، ولكن أُضيف في SUSv3) لتحويل a، يُحوّل معطى double إلى تدوين ست عشري (باستخدام الأحرف abcdef) بالنمط [-]0xh.hhhhp±d؛ أما لتحويل A فيُستخدم البادئة 0X والأحرف ABCDEF وفاصل الأس P. يوجد رقم ست عشري واحد قبل الفاصلة العشرية، وعدد الأرقام بعدها يساوي الدقة. تكفي الدقة المبدئية لتمثيل دقيق للقيمة إذا كان هناك تمثيل دقيق في الأساس 2، وإلا فإنها تكون كبيرة بما يكفي لتمييز القيم من النوع double. الرقم قبل الفاصلة العشرية غير محدد للأرقام غير المعييرة، وغير صفري ولكنه غير محدد للأرقام المعييرة. يحتوي الأس دائماً على رقم واحد على الأقل؛ وإذا كانت القيمة صفراً، فإن الأس يكون 0.
إذا لم يكن هناك معدل l، يُحول معامل int إلى unsigned char، ويُكتب المحرف الناتج. إذا وُجد معدل l، يُحول معامل wint_t (محرف واسع) إلى تسلسل متعدد البايتات عن طريق استدعاء الدالة wcrtomb(3)، مع حالة تحويل تبدأ في الحالة المبدئية، وتُكتب السلسلة متعددة البايتات الناتجة.
في حال عدم وجود معدّل l: يُتوقع أن يكون معطى const char * مؤشراً إلى مصفوفة من نوع محارف (مؤشر إلى سلسلة نصية). تُكتب المحارف من المصفوفة وصولاً إلى (دون تضمين) بايت الخلو المنتهي ('\0')؛ وإذا حُددت الدقة، فلا يُكتب أكثر من العدد المحدد. إذا أُعطيت الدقة، فلا يشترط وجود بايت الخلو؛ أما إذا لم تُحدد الدقة، أو كانت أكبر من حجم المصفوفة، فيجب أن تحتوي المصفوفة على بايت خلو منتهٍ.
في حال وجود معدّل l: يُتوقع أن يكون معطى const wchar_t * مؤشراً إلى مصفوفة من المحارف العريضة. تُحوّل المحارف العريضة من المصفوفة إلى محارف متعددة البايتات (كل منها عبر استدعاء للدالة wcrtomb(3)، مع حالة تحويل تبدأ من الحالة الأولية قبل أول محرف عريض)، وصولاً إلى محرف الخلو العريض المنتهي وتضمينه. تُكتب المحارف متعددة البايتات الناتجة وصولاً إلى (دون تضمين) بايت الخلو المنتهي. إذا حُددت الدقة، فلا يُكتب أكثر من عدد البايتات المحدد، ولكن لا تُكتب محارف متعددة بايتات جزئية. لاحظ أن الدقة تحدد عدد البايتات المكتوبة، وليس عدد المحارف العريضة أو مواقع الشاشة. يجب أن تحتوي المصفوفة على محرف خلو عريض منتهٍ، ما لم تُعطَ دقة صغيرة جداً بحيث يتجاوزها عدد البايتات المكتوبة قبل الوصول إلى نهاية المصفوفة.
(ليس في C99 أو C11، ولكنه في SUSv2 وSUSv3 وSUSv4.) مرادف لـ lc. لا تستخدمه.
(ليس في C99 أو C11، ولكنه في SUSv2 وSUSv3 وSUSv4.) مرادف لـ ls. لا تستخدمه.
يُطبع معطى المؤشر void * بالتمثيل الست عشري (كما لو كان عبر %#x أو %#lx).
يُخزن عدد المحارف المكتوبة حتى الآن في العدد الصحيح الذي يشير إليه المعطى المقابل. يجب أن يكون هذا المعطى من نوع int *، أو ناعاً يطابق حجمه معدّل طول العدد الصحيح المرفق (اختيارياً). لا يُحوّل أي معطى. (هذا المحدد غير مدعوم في مكتبة bionic C.) السلوك غير محدد إذا تضمن تخصيص التحويل أي أعلام أو عرض حقل أو دقة.
(امتداد glibc؛ مدعوم بواسطة uClibc وmusl.) يطبع مخرجات strerror(errno) (أو strerrorname_np(errno) في الشكل البديل). لا يتطلب أي معطى.
%
تُكتب العلامة '%'. لا يُحوّل أي معطى. تخصيص التحويل الكامل هو '%%'.

قيمة الإرجاع

عند العودة بنجاح، تعيد هذه الدوال عدد البايتات المطبوعة (باستثناء بايت الخلو المستخدم لإنهاء المخرجات إلى السلاسل النصية).

لا تكتب الدالتان snprintf() وvsnprintf() أكثر من size بايت (بما في ذلك بايت الخلو المنتهي ('\0')). إذا بُترت المخرجات بسبب هذا الحد، فإن القيمة المعادة هي عدد المحارف (باستثناء بايت الخلو المنتهي) التي كانت ستُكتب في السلسلة النهائية لو توفرت مساحة كافية. وبذلك، فإن القيمة المعادة التي تساوي size أو أكثر تعني أن المخرجات قد بُترت. (انظر أيضاً أدناه تحت التنبيهات CAVEATS.)

إذا واجه خطأ في المخرجات، تُعاد قيمة سالبة.

السمات

للاطلاع على شرح للمصطلحات المستخدمة في هذا القسم، انظر attributes(7).

الواجهة السمة القيمة
printf(), fprintf(), sprintf(), snprintf(), vprintf(), vfprintf(), vsprintf(), vsnprintf() سلامة الخيوط المنطقة (locale) آمنة لتعدد المسالك (MT-Safe)

المعايير

C11, POSIX.1-2008.
جنو، POSIX.1-2008.

التاريخ

C89, POSIX.1-2001.
SUSv2, C99, POSIX.1-2001.
بخصوص القيمة المعادة من snprintf()، يتعارض SUSv2 وC99: عندما تُستدعى snprintf() مع size=0، يشترط SUSv2 قيمة معادة غير محددة أقل من 1، بينما يسمح C99 لـ str بأن يكون NULL في هذه الحالة، ويعطي القيمة المعادة (كما هو الحال دائماً) كعدد المحارف التي كانت ستُكتب لو كانت سلسلة المخرجات كبيرة بما يكفي. توافق مواصفات POS.1-2001 وما بعدها snprintf() مع C99.
جنو، POSIX.1-2008.

أضاف glibc 2.1 معدلات الطول hh وj وt وz وأحرف التحويل a وA.

أضاف glibc 2.2 حرف التحويل F بدلالات C99، وحرف العلم I.

أعطى glibc 2.35 معنى للشكل البديل (#) لمحدد التحويل m، وهو %#m.

تحذيرات

تعتمد بعض البرامج بتهور على كود مثل الآتي


sprintf(buf, "%s some further text", buf);

لإلحاق نص بـ buf. ومع ذلك، تذكر المعايير صراحةً أن النتائج غير محددة إذا تداخلت مخازن المصدر والوجهة عند استدعاء sprintf() و snprintf() و vsprintf() و vsnprintf(). اعتمادًا على إصدار gcc(1) المستخدم، وخيارات المجمع الموظفة، فإن استدعاءات مثل المذكورة أعلاه لن تنتج النتائج المتوقعة.

يتوافق تطبيق glibc للدالتين snprintf() وvsnprintf() مع معيار C99، أي أنه يتصرف كما هو موضح أعلاه، وذلك منذ الإصدار glibc 2.1. حتى الإصدار glibc 2.0.6، كانتا تعيدان -1 عند بتر المخرجات.

العلل

نظرًا لأن sprintf() و vsprintf() تفترضان سلسلة نصية طويلة عشوائيًا، يجب على المستدعِي الحذر من تجاوز المساحة الفعلية؛ وغالبًا ما يستحيل ضمان ذلك. لاحظ أن طول السلاسل المنتجة يعتمد على المحلية ويصعب توقعه. استخدم snprintf() و vsnprintf() بدلاً من ذلك (أو asprintf(3) و vasprintf(3)).

غالبًا ما يشير كود مثل printf(foo); إلى علة، بما أن foo قد تحتوي على المحرف %. إذا كانت foo تأتي من مدخلات مستخدم غير موثوقة، فقد تحتوي على %n، مما يسبب كتابة استدعاء printf() في الذاكرة وإنشاء ثغرة أمنية.

أمثلة

لطباعة Pi حتى خمس مراتب عشرية:


#include <math.h>
#include <stdio.h>
fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0));

لطباعة التاريخ والوقت بصيغة "الأحد، 3 يوليو، 10:02"، حيث weekday و month مؤشرات إلى سلاسل:


#include <stdio.h>
fprintf(stdout, "%s, %s %d, %.2d:%.2d\n",

weekday, month, day, hour, min);

تستخدم العديد من البلدان ترتيب يوم-شهر-سنة. ومن ثم، يجب أن تكون النسخة المدوّلة قادرة على طباعة المعطيات بترتيب يحدده التنسيق:


#include <stdio.h>
fprintf(stdout, format,

weekday, month, day, hour, min);

حيث يعتمد format على المحلية، وقد يبدل المعاملات. مع القيمة:


"%1$s, %3$d. %2$s, %4$d:%5$.2d\n"

قد يحصل المرء على "Sonntag, 3. Juli, 10:02".

لتخصيص سلسلة كبيرة بما يكفي والطباعة فيها (كود صحيح لكل من glibc 2.0 و glibc 2.1):

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *
make_message(const char *fmt, ...)
{

int n = 0;
size_t size = 0;
char *p = NULL;
va_list ap;
/* Determine required size. */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
if (n < 0)
return NULL;
size = (size_t) n + 1; /* One extra byte for '\0' */
p = malloc(size);
if (p == NULL)
return NULL;
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
if (n < 0) {
free(p);
return NULL;
}
return p; }

إذا حدث البتر في إصدارات glibc الأقدم من 2.0.6، فيُعامل هذا كخطأ بدلاً من التعامل معه بلباقة.

انظر أيضًا

printf(1)، asprintf(3)، puts(3)، scanf(3)، setlocale(3)، strfromd(3)، wcrtomb(3)، wprintf(3)، locale(5)

ترجمة

تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.

15 يونيو 2024 صفحات دليل لينكس 6.9.1