Поскольку «m» является целым числом, он не должен принимать p2-p1 в качестве входных данных, поскольку p1 и p2 оба являются указателями, а m является целым числом, оно должно выдавать ошибку типа «недопустимое преобразование из« int »в« int »», но это не так. Почему?
Спецификация C++ объявляет это допустимым.
Из спецификации C++11 5.7.6:
Когда два указателя на элементы одного и того же объекта массива вычитаются, результатом является разница индексов двух элементов массива. Тип результата — определяемый реализацией целочисленный тип со знаком; этот тип должен быть тем же типом, который определен как std::ptrdiff_t в заголовке (18.2).
... далее в этом абзаце...
Если оба указателя не указывают на элементы одного и того же объекта массива или один за последним элементом объекта массива, поведение не определено.
Результат p2 - p1 имеет тот же тип, что и std::ptrdiff_t, но ничего не говорит о том, что компилятор не может определить его как
namspace std {
typedef ptrdiff_t int;
}
Однако вы также не получаете гарантии, что это будет работать на всех платформах. Например, некоторые платформы (особенно 64-битные) будут использовать длинное значение для ptrdiff_t. На этих платформах ваш код не сможет скомпилироваться, потому что он зависит от определенного типа реализации для ptrdiff_t.
Что касается вашего второго вопроса, формулировка в спецификации С++ 5.7.6 предполагает, почему они работают так, как работают. Формулировка указывает на то, что авторы языка хотели, чтобы арифметика указателей поддерживала быструю арифметику при работе с массивом. Соответственно, определенный результат вычитания указателя дает удобные результаты при использовании в контексте манипулирования массивом. Вы можете создать язык, в котором разница между двумя указателями равна разнице между их адресами памяти в байтах, и у вас будет согласованный рабочий язык. Тем не менее, хороший язык всегда приносит наибольшую отдачу. Авторы считали, что чистое манипулирование массивами более ценно, чем возможность получить разницу в байтах. Например:
double* findADouble(double* begin, double* end, double valueToSearchFor)
{
for (double* iter = begin; iter != end; iter++) {
if (*iter == valueToSearchFor)
return iter;
}
return 0;
}
В нем должен быть sizeof, и нам пришлось бы использовать += вместо ++.
double* findADouble(double* begin, double* end, double valueToSearchFor)
{
for (double* iter = begin; iter != end; iter += sizeof(double)) {
if (*iter == valueToSearchFor)
return iter;
}
return 0;
}
Также стоит отметить в их решении: когда правило было создано на C, оптимизирующие компиляторы не очень хорошо справлялись со своей работой. iter += sizeof(double) может быть скомпилирован в гораздо менее эффективный ассемблерный код, чем ++iter, даже если эти две операции в основном делают одно и то же. У современных оптимизаторов с этим проблем нет, но синтаксис остается.
person
Cort Ammon
schedule
02.09.2013