Можем ли мы вычесть нулевые указатели? - PullRequest
5 голосов
/ 18 апреля 2019

Поскольку арифметика указателей определена в том же массиве, я сомневаюсь, что мы можем вычесть NULL из другого NULL. Я обеспокоен реализацией:

//first and second can both either be from the same array 
//or be both NULL
prtdiff_t sub(void *first, void *second){
    //Do I really need this condition?
    if(!first && !second)
        return (ptrdiff_t) 0;

    return second - first;
}

Ответы [ 4 ]

8 голосов
/ 18 апреля 2019

Вычитание двух пустых указателей не допускается. Раздел 6.5.6p9 C стандартных состояний :

Когда вычтены два указателя, оба должны указывать на элементы тот же объект массива, или один за последним элементом массива объект; Результатом является разница подписчиков два элемента массива. Размер результата определяется реализацией, и ее тип (целочисленный тип со знаком) ptrdiff_t определен в заголовке. Если результат не представимое в объекте этого типа, поведение не определено. Другими словами, если выражения P и Q указывают на соответственно я -й и й -й элемент массива, выражение (P) - (Q) имеет значение i-j, если это значение соответствует объекту типа ptrdiff_t. Более того, если выражение P указывает либо на элемент объекта массива, либо один за последним элементом объекта массива и выражение Q указывает на последний элемент того же объекта массива, выражение ((Q) +1) - (P) имеет то же значение, что и ((Q) - (P)) + 1, и как - ((P) - ((Q) +1)), и имеет значение ноль, если выражение P указывает один за последним элементом массива, даже хотя выражение (Q) +1 не указывает на элемент массива объект.

Поскольку ни один указатель не указывает на объект массива, поведение не определено.

Вы также не можете вычесть два void *, потому что void является неполным типом, и вычитание указателя зависит от знания размера объекта, на который указывает указатель. Вы можете привести каждый указатель к intptr_t и вычесть их, однако это даст вам разницу в байтах между указателями, а не разность индексов.

6 голосов
/ 18 апреля 2019

Нет, вы не можете сделать это: разница между двумя указателями определяется только для указателей, которые указывают на элементы одного и того же массива или один за концом. (Для этой цели объект считается массивом из одного элемента).

(intptr_t)second - (intptr_t)first действительно, хотя.

0 голосов
/ 18 апреля 2019

Простой ответ: NO, YOU CAN'T SUBTRACT A NULL FROM ANOTHER NULL.

Я думаю, вы неправильно поняли это определение:

NULL четко определен как: целочисленное константное выражение с значение 0 или такое выражение, приведенное к типу void, называется нулевым константа указателя. Так что я думал, что мы можем вычесть один 0 из еще 0.

Теперь, давайте пока возьмем определение GOOGLE NULL

Нуль означает, что не имеет значения ; другими словами, ноль равен нулю, как если бы вы добавьте в кофе так мало сахара, что он станет практически нулевым. Ноль также означает недействительным. От латинского nullus, значение «не любой», бедный, бессильный ноль на самом деле вообще не существует.

Ясно, что в нем говорится, что null не имеет значения . Думайте об этом, как вы пытаетесь ничего не вычитать из ничего .

Теперь давайте возьмем это другими словами, ноль равен нулю (если и только если определено значение), вы можете вычесть это наверняка (но не можете сделать что-то вроде char * ab = NULL, char * aa = NULL и затем выполнить вычитание как ab-aa все еще незаконно)

Но никто не может на самом деле предсказать значение для нуля, поэтому, когда вы не можете получить значение, вы не можете выполнить какую-либо операцию (например, вычитание, сложение и т. Д.) Над этим.

0 голосов
/ 18 апреля 2019

C ++ 03 §5.7 / 7 гласит:

Если значение 0 добавляется или вычитается из значения указателя, Результат сравнивается равным исходному значению указателя. Если два указателя указывают на один и тот же объект или оба указывают один за концом того же массив или оба равны нулю, и два указателя вычитаются, Результат сравнивается равным значению 0, преобразованному в тип ptrdiff_t.

Но нет такого положения для C.

...