هذا استخدام غير صحيح من تقييد المؤشرات ؟
-
27-09-2019 - |
سؤال
لنفترض أن لدي مجموعة كبيرة وأنا حساب مؤشر إلى تمريرها إلى وظيفة ثانية.كمثال بسيط, شيء من هذا القبيل:
void foo(float* array, float c, unsigned int n)
{
for (unsigned int i = 0; i < n; ++i)
array[i] *= c;
}
void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int n)
{
for (unsigned int i = 0; i < m; ++i)
foo(&array[i * n], array2[i], n);
}
هذا كسر قواعد تقيد في شريط() حيث يمكنك تمرير عنوان جزء من مجموعة فو () ، حتى إذا كان لا يمكنك استخدام اسم مستعار جزء من مجموعة ضمن شريط()?
المحلول
(جميع الاستشهادات الرجوع إلى N1256, الذي هو C99 بالإضافة إلى التقنية والتصويبات (TC3).)
والتعريف الرسمي restrict
ويرد في الفقرة 6.7.3.1.أقتبس أهم subclause أدناه. P
هو restrict
-مؤهل مؤشر إلى نوع T
نطاقها هو كتلة B
.مؤشر التعبير E
هو ان يكون على أساس P
إذا كان يعتمد على قيمة P
في حد ذاته لا قيمة P
من النقاط.
خلال كل إعدام
B
, اسمحواL
أي lvalue له&L
على أساس P.إذاL
يستخدم للوصول إلى قيمة الكائنX
أن يعين ،X
كما تم تعديل (بأي وسيلة) ، ثم تنطبق الشروط التالية:
T
لا يجوز const-مؤهل.- كل lvalue المستخدمة للوصول إلى قيمة
X
كما يجب أن يكون عنوان القائمة علىP
.- كل ذلك يعدل
X
يعتبر أيضا إلى تعديلP
, لأغراض هذا subclause.- إذا
P
يتم تعيين قيمة المؤشر التعبيرE
استنادا إلى آخر مقيد مؤشر كائنP2
, المرتبطة مع كتلةB2
, ثم إما تنفيذB2
يجب أن تبدأ قبل تنفيذB
, أو تنفيذB2
يجب أن تنتهي قبل التعيين.إذا كان يتم استيفاء هذه الشروط ، ثم سلوك غير معرف.
دعونا ننظر إلى ما القواعد يجب أن أقول عن الوصول إلى أجزاء من bar
's array
في foo
.نبدأ مع array
, تقييد مؤهل مؤشر أعلن في المعلمة قائمة bar
.من أجل الوضوح ، سوف ألفا-تحويل المعلمات foo
:
void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }
التخزين إلى جانب array
كما يتم تعديل من خلال b
.وهذا موافق مع بالنقطة الثانية كما &array[i*n]
ما يعادل array+(i*n)
(انظر §6.5.3.2).
إذا b
كان تقييد مؤهل, ثم سيكون علينا التحقق الرابع النقطة مع P
←b
, B
←foo
, P2
←array
, B2
←bar
.منذ B
هو تداخل داخل B2
(وظائف تتصرف كما لو المضمنة هنا نرى §6.7.3.1.11), الشرط الأول.هناك أيضا واحد instanciation من النقطة الثالثة (الوصول إلى b[i]
في foo
) وهي ليست مشكلة.
ومع ذلك b
لا تقييد المؤهلين.وفقا ل §6.3.2.3.2, "أي تصفيات س, مؤشر إلى غيرس-مؤهل نوع يمكن تحويلها إلى مؤشر س-مؤهل نسخة من نوع ؛ القيم المخزنة في الأصلي وتحويلها مؤشرات يقارن متساوية".ولذلك التحويل من array+(i*n)
إلى b
محددة و واضحة المعنى ، لذلك البرنامج سلوك محدد.وعلاوة على ذلك ، منذ b
لا restrict
-مؤهل, أنها لا تحتاج إلى طاعة أي الخطي الشرط.على سبيل المثال التالي foo
هو قانوني في تركيبة مع bar
:
void qux(float *v, float *w) {
v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
qux(b,b);
}
وأضاف:إلى العنوان الخاص بك محددة قلق "في شريط() حيث يمكنك تمرير عنوان جزء من مجموعة فو()", هذا هو غير هذه المسألة: restrict
ينطبق على المؤشر ، وليس مجموعة ، ويمكنك أداء الحساب على ذلك (النقطة 2).
نصائح أخرى
لا ، فإن تقييد يعني أن الصفيف لا يمكنه التعبير عن أي شيء ، بحيث يمكنك تمرير الأشياء دون كسر القواعد