&(p->x); // is this undefined behavior?
Стандартът е малко неясен по отношение на това:
[expr.ref] ... Изразът E1-›E2 се преобразува в еквивалентната форма (*(E1)).E2;
[expr.unary.op] Унарният * оператор ... резултатът е lvalue, отнасящ се до обекта ... към който сочи изразът.
В раздела не се споменава изрично UB. Цитираното правило изглежда противоречи на факта, че нулевият указател не сочи към никакъв обект. Това може да се тълкува, че да, поведението е недефинирано.
[expr.unary.op] Резултатът от унарния & оператор е указател към неговия операнд. ... ако операндът е lvalue от тип T, резултантният израз е prvavalue от тип „указател към T“, чийто резултат е указател към посочения обект ([intro.memory]).
Отново не съществува определен обект. Обърнете внимание, че в нито един момент операндът lvalue не се преобразува в rvalue, което определено би било UB.
През 2000 г. имаше проблем с CWG към изяснете дали индиректността през null е недефинирана. Предложената резолюция (2004), която би изяснила, че индиректността чрез null е не UB, изглежда не е добавена към стандарта досега.
Но дали е или не е UB, няма голямо значение, тъй като не е необходимо да правите това. Най-малкото полученият указател ще бъде невалиден и следователно безполезен.
Ако сте планирали да преобразувате указателя в цяло число, за да получите отместването на члена, няма нужда да правите това, защото вместо това можете да използвате макроса offsetof
от стандартната библиотека, която няма UB.
&(p[1]); // undefined?
Тук поведението е съвсем ясно недефинирано:
[expr.sub] ... Изразът E1[E2] е идентичен (по дефиниция) на *((E1)+(E2)), с изключение на това, че в случай на операнд от масив, резултатът е lvalue, ако този операнд е lvalue и xvalue в противен случай.
[expr.add] Когато израз J, който има интегрален тип, се добави или извади от израз P от тип указател, резултатът има тип P.
Ако P се оценява на нулева стойност на указателя и J се оценява на 0 (не се прилага)
В противен случай, ако P сочи към елемент от масив (не се прилага)
В противен случай поведението е недефинирано.
&(p[0]); // undefined?
Съгласно предходните правила се прилага първата опция:
Ако P се изчисли като стойност на нулев указател и J се изчисли на 0, резултатът е стойност на нулев указател.
И сега се връщаме към въпроса дали индиректността през тази нула е UB. Вижте началото на отговора.
Все пак няма особено значение. Няма нужда да пишете това, тъй като това е просто ненужно сложен начин за писане на sizeof(int) * i
(като i
е съответно 1 и 0).
person
eerorika
schedule
12.06.2020
p
, така че дори преди да вземете адреса, да направитеp->x
е същото като(*p).x
, което е UB. - person cigien   schedule 12.06.2020