سؤال

لأسباب لا أتفق معها تمامًا ، لكن "القوى (المضادة للاستخدام) التي تكون" تستمر في المرسوم على الرغم من اعتراضاتي ، لديّ روتين فرز يقارن بـ STRCMP () الأساسي بالفرز باسمه. إنه يعمل بشكل رائع. من الصعب الحصول على هذا الخطأ. ومع ذلك ، في الساعة الحادية عشرة ، تقرر أن الإدخالات التي تبدأ برقم يجب أن تأتي بعد الإدخالات التي تبدأ برسالة ، على عكس أمر ASCII. يستشهدون بأن معيار eBCDIC له أرقام يتبع رسائل ، لذا فإن الافتراض السابق ليس حقيقة عالمية ، وليس لديّ القدرة على الفوز بهذه الحجة ... لكنني استطراد.

في ذلك يكمن مشكلتي. لقد استبدلت جميع المراجع المناسبة لـ STRCMP بوظيفة جديدة استدعاء NonStd_strcmp ، وأصبحت الآن بحاجة إلى تنفيذ التعديلات لإنجاز تغيير الفرز. لقد استخدمت مصدر FreeBSD كقاعدتي: http://freebsd.active-venture.com/freebsd-srctree/newsrc/libkern/strncmp.c.html

 if (n == 0)
  return (0);
 do {
  if (*s1 != *s2++)
   return (*(const unsigned char *)s1 -
    *(const unsigned char *)(s2 - 1));
  if (*s1++ == 0)
   break;
 } while (--n != 0);
 return (0);

أعتقد أنني قد أحتاج إلى قضاء بعض الوقت بعيدًا للتفكير حقًا في كيفية القيام بذلك ، لكنني متأكد من أنني لست الشخص الوحيد الذي عانى من التغيرات في المواصفات المواصفات.

هل كانت مفيدة؟

المحلول

في هذه الحالة الخاصة مع فقط أحرف كبيرة (كما ذكرها OP في التعليقات) والأرقام 0-9 ، يمكنك أيضًا حذف جدول الطلبات وبدلاً من ذلك تضاعف كلا الشخصين المختلفين بمقدار 4 ومقارنة النتائج Modulo 256. نطاق أرقام ASCII (48 إلى 57) لا تغلب على 8 بت (57 × 4 = 228) ، ولكن نطاق الأحرف الكبيرة (65 إلى 90) سوف (65 × 4 = 260). عندما نقارن القيم المضاعفة Modulo 256 ، ستكون القيمة لكل حرف أقل من أي رقم: 90 × 4 ٪ 256 = 104 <192 = 48 × 4

قد يبدو الرمز شيئًا مثل:

int my_strcmp (const char *s1, const char *s2) {
    for (; *s1 == *s2 && *s1; ++s1, ++s2);
    return (((*(const unsigned char *)s1) * 4) & 0xFF) - \
           (((*(const unsigned char *)s2) * 4) & 0xFF);
}

بالطبع ، يكون حل جدول الطلب أكثر تنوعًا بشكل عام لأنه يسمح للمرء بتحديد ترتيب الفرز لكل حرف - هذا الحل معقول فقط لهذه الحالة الخاصة مع الأحرف الكبيرة الرسائل مقابل الأرقام. (ولكن على سبيل المثال على منصات متحكم ، يمكن أن يكون توفير الكمية الصغيرة من الذاكرة المستخدمة من قبل الجدول فائدة حقيقية.)

نصائح أخرى

ما عليك القيام به هو إنشاء جدول طلب لكل حرف. هذه هي أيضًا أسهل طريقة لإجراء مقارنات غير حساسة للحالة.

if (order_table[*s1] != order_table[*s2++])

كن على دراية بأن الأحرف قد يتم توقيعها ، وفي هذه الحالة قد يصبح الفهرس لجدولك سلبيًا. هذا الرمز مخصص لـ chars فقط:

int raw_order_table[256];
int * order_table = raw_order_table + 128;
for (int i = -128;  i < 128;  ++i)
    order_table[i] = (i >= '0' && i <= '9') ? i + 256 : toupper(i);

إذا كانت القوى الخاصة بك-مثل كل القوى الأخرى-التي أتيحت لها ، فقد ترغب في جعلها خيارًا (حتى لو كانت مخفية):

امر ترتيب:

أ أرقام بعد الحروف

يا رسائل بعد الأرقام

أو الأسوأ من ذلك ، قد يكتشفون أنهم يريدون فرز الأرقام عدديًا (على سبيل المثال يأتي "A123" بعد، بعدما "A15") ، ثم يمكن أن يكون

أ أرقام بعد الحروف

يا رسائل بعد الأرقام

o الأرقام الذكية بعد الحروف

س رسائل بعد الأرقام الذكية

هذا يحصل على تشخيص المشكلة الحقيقية ، وليس الأعراض. أراهن أن هناك فرصة بسيطة لأنهم قد يغيرون رأيهم في الساعة 11 و 59 دقيقة.

يمكنك استخدام جدول البحث لترجمة ASCII إلى ebcdic عند مقارنة الشخصيات ؛-)

على الرغم من اتفاق عام مع الإجابات أعلاه ، أعتقد أنه من السخف إجراء عمليات بحث لكل تكرار للحلقة ، إلا إذا كنت تعتقد أن معظم المقارنات سيكون لها أحرف أولى مختلفة ، عندما يمكنك بدلاً من ذلك القيام بذلك

char c1, c2;
while((c1 = *(s1++)) == (c2 = *(s2++)) && c1 != '\0');
return order_table[c1] - order_table[c2];

أيضًا ، أود أن أوصي ببناء order_table باستخدام مُهيئ ثابت ، والذي سيحسن السرعة (لا حاجة لتوليدها في كل مرة - أو على الإطلاق)

إليك ما ينبغي أن يكون تطبيقًا جيدًا للسلسلة مقارنة بين المنشورات الأخرى الموصوفة في المشاركات الأخرى.

static const unsigned char char_remap_table[256] = /* values */

#define char_remap(c) (char_remap_table[(unsigned char) c])

int nonstd_strcmp(const char * restrict A, const char * restrict B) {
     while (1) {
          char a = *A++;
          char b = *B++;
          int x = char_remap(a) - char_remap(b);
          if (x) {
               return x;
          }
          /* Still using null termination, so test that from the original char,
           * but if \0 maps to \0 or you want to use a different end of string
           * then you could use the remapped version, which would probably work
           * a little better b/c the compiler wouldn't have to keep the original
           * var a around. */
          if (!a) { /* You already know b == a here, so only one test is needed */
               return x;  /* x is already 0 and returning it allows the compiler to
                           * store it in the register that it would store function
                           * return values in without doing any extra moves. */
          }
     }
}

علاوة على ذلك ، يمكنك تعميم الوظيفة لأخذ char_remap_table كمعلمة تتيح لك استخدام تعيينات مختلفة بسهولة في وقت لاحق إذا كنت بحاجة إلى ذلك.

int nonstd_strcmp(const char * restrict a, const char * restrict b, const char * restrict map);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top