Поблочное тестирование работает очень похожее на двойную бухгалтерию. Вы заявляете то же самое (бизнес-правило) двумя очень отличающимися способами (как запрограммированные правила в Вашем производственном коде, и как простые, представительные примеры в Ваших тестах). Очень маловероятно, что Вы делаете тот же ошибка в обоих, поэтому если они оба соглашаются друг с другом, довольно маловероятно, что Вы поняли его превратно.
, Как тестирует попытку стоить усилия? По моему опыту, по крайней мере четырьмя способами, по крайней мере, при выполнении разработки через тестирование:
b - a
is a ptrdiff_t
, which you can print with %td
in your printf
format. From the spec section 6.5.6 Additive operators:
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is
ptrdiff_t
defined in theheader.
For printf
and related functions, section 7.19.6 Formatted input/output functions:
t
Specifies that a followingd
,i
,o
,u
,x
, orX
conversion specifier applies to aptrdiff_t
or the corresponding unsigned integer type argument; or that a followingn
conversion specifier applies to a pointer to aptrdiff_t
argument.
I poked around in the spec some more, and it seems to indicate that a difference of two pointers might not even fit in a ptrdiff_t
, in which case behaviour is undefined:
J.2 Undefined behavior
- The result of subtracting two pointers is not representable in an object of typeptrdiff_t
(6.5.6).
Though I can't imagine any implementation where that might come up. I guess you could check PTRDIFF_MIN
and PTRDIFF_MAX
in
to be really sure.
Результат b - a
определяется только тогда, когда оба a
и b
указывают на элементы одного и того же массива char. Это требование также можно интерпретировать как a
и b
, указывающие на байты, принадлежащие одному и тому же объекту, поскольку каждый объект может быть повторно интерпретирован как массив символов.
В противном случае, результат не определен. Т.е. попытка вычесть такие указатели приводит к неопределенному поведению.
Когда результат определен, он имеет тип ptrdiff_t
. ptrdiff_t
- это имя typedef, и какой тип скрывается за этим именем typedef, определяется реализацией. Однако известно, что тип подписан.
Также обратите внимание, этот язык C не гарантирует, что ptrdiff_t
достаточно велик, чтобы содержать результат любого вычитания, даже если указатели указывают на элементы одного и того же массива. Если указатели расположены слишком далеко друг от друга для типа ptrdiff_t
, чтобы учесть результат, поведение не определено.
Нет специального спецификатора формата printf
для ptrdiff_t
даже в C99, поэтому вам, вероятно, будет лучше преобразовать его в достаточно большой целочисленный тип со знаком и использовать спецификатор формата для этого типа
printf("%ld\n", (long) (b - a));
Исправление: C99 действительно имеет модификатор длины для ptrdiff_t
. Правильный способ распечатать результат в C99:
printf("%td\n", b - a);
Обратите внимание, что t
- это модификатор длины. Его можно комбинировать с d
, o
, Спецификаторы преобразования u
, x
или X
, в зависимости от того, какой выходной формат вы хотите получить. В C89 / 90 вам все равно придется использовать достаточно большой подписанный тип.
PS Вы сказали, что не можете себе представить, что он потерпит неудачу на 32-битной или 64-битной машине. На самом деле очень легко вообразить (или фактически допустить) неудачу. Вы видите ptrdiff_t
на 32-битной машине обычно 32-битного типа. Поскольку это тип со знаком, у него есть только 31 бит для представления величины значения. Если вы возьмете два указателя, которые находятся дальше друг от друга (т.е. требуется 32 бита для представления «расстояния»), результат b - a
будет переполняться и будет бессмысленным. Чтобы предотвратить эту неудачу, вы d требуется как минимум 33-битный подписанный ptrdiff_t
на 32-битной машине и как минимум 65-битный подписанный ptrdiff_t
на 64-битной машине. Реализации обычно этого не делают, они просто используют «разрешение» из стандарта для получения неопределенного поведения при переполнении.
It's ptrdiff_t
. From man stddef.h
:
ptrdiff_t Signed integer type of the result of subtracting two pointers.
Print it with %td
.
Поскольку вы не инициализировали переменные a и b , код дает неопределенное поведение. Но кроме этого, типом ba является ptrdiff_t , который достаточно велик, чтобы вместить результат. Если у вас достаточно современный C, вы можете распечатать его с помощью % tx .
Если вы не хотите использовать % tx , вы должны преобразовать свой результат, чтобы он действительно соответствует (и не случайно) вашему спецификатору формата:
printf("%lx", (unsigned long)(a-b));
Не исключено, что система может иметь, например, 32-битное адресное пространство и 32-битный ptrdiff_t, но 64-битный длинный, а затем ваш printf завершится ошибкой.
t инициализировал переменные a и b , код дает неопределенное поведение. Но кроме этого, типом ba является ptrdiff_t , который достаточно велик, чтобы вместить результат. Если у вас достаточно современный C, вы можете распечатать его с помощью % tx .Если вы не хотите использовать % tx , вы должны преобразовать свой результат, чтобы он действительно совпадает (и не случайно) с вашим спецификатором формата:
printf("%lx", (unsigned long)(a-b));
Не исключено, что система может иметь, например, 32-битное адресное пространство и 32-битный ptrdiff_t, но 64-битную длину, а затем ваш printf завершится ошибкой.
t инициализировал переменные a и b , код дает неопределенное поведение. Но кроме этого, типом ba является ptrdiff_t , который достаточно велик, чтобы вместить результат. Если у вас достаточно современный C, вы можете распечатать его с помощью % tx .Если вы не хотите использовать % tx , вы должны преобразовать свой результат, чтобы он действительно совпадает (и не случайно) с вашим спецификатором формата:
printf("%lx", (unsigned long)(a-b));
Не исключено, что система может иметь, например, 32-битное адресное пространство и 32-битный ptrdiff_t, но 64-битную длину, а затем ваш printf завершится ошибкой.
который достаточно велик, чтобы вместить результат. Если у вас достаточно современный C, вы можете распечатать его с помощью % tx .Если вы не хотите использовать % tx , вы должны преобразовать свой результат, чтобы он действительно совпадает (и не случайно) с вашим спецификатором формата:
printf("%lx", (unsigned long)(a-b));
Не исключено, что система может иметь, например, 32-битное адресное пространство и 32-битный ptrdiff_t, но 64-битную длину, а затем ваш printf завершится ошибкой.
который достаточно велик, чтобы вместить результат. Если у вас достаточно современный C, вы можете распечатать его с помощью % tx .Если вы не хотите использовать % tx , вы должны преобразовать свой результат, чтобы он действительно соответствует (и не случайно) вашему спецификатору формата:
printf("%lx", (unsigned long)(a-b));
Не исключено, что система может иметь, например, 32-битное адресное пространство и 32-битный ptrdiff_t, но 64-битный длинный, а затем ваш printf завершится ошибкой.