Здравствуйте, Erop, Вы писали:
E>Встретил на ревью, юзали в качестве lengthof. E>Написал, что нестандартно, опасно и не константа времени компиляции + UB. E>Попросили аргументировать по UB, так как это а-та-та и депримирование вплоть до увольнения...
скажи им что вместо & надо использовать std::addressof
Здравствуйте, Erop, Вы писали:
J>>А зачем вообще это нужно? Какую задачу ты решаешь этим кодом? E>Встретил на ревью, юзали в качестве lengthof. E>Написал, что нестандартно, опасно и не константа времени компиляции + UB.
#include <type_traits>
int main()
{
char array[1][11];
static_assert(std::is_same<decltype((1[&array[0]])), decltype((array[1]))>::value, "");
static_assert(&1[&array[0]] == &array[1], "");
array[1]; // line #10
array[1]-&array[0][0]; // line #11
1[&array[0]]-&array[0][0]; // line #13
1[&array[0]]-&array[0][0]; // line #14
}
clang++ -std=c++11 -O0 -Wall -Wno-unused-value -pedantic -pthread main.cpp && ./a.out
main.cpp:10:5: warning: array index 1 is past the end of the array (which contains 1 element) [-Warray-bounds]
array[1]; // line #10
^ ~
main.cpp:5:5: note: array 'array' declared here
char array[1][11];
^
main.cpp:11:5: warning: array index 1 is past the end of the array (which contains 1 element) [-Warray-bounds]
array[1]-&array[0][0]; // line #11
^ ~
main.cpp:5:5: note: array 'array' declared here
char array[1][11];
^
2 warnings generated.
Clang во втором случае warning не выдаёт, но я думаю это скорей всего недоработка.
Достаточно доказать ссылаясь на пункты ISO тождественное равенство array[1] и 1[&array[0]], чтобы заручится поддержкой Clang'а.
E>Попросили аргументировать по UB, так как это а-та-та и депримирование вплоть до увольнения...
Это Хотя молодцы
E>В целом я тоже считаю, что это UB, так как 1[&array] -- разыменование.
Здравствуйте, XuMuK, Вы писали:
XMK>оффтоп: XMK>а чем такой вариант принципиально лучше шаблона jazzer'a или стандартного sizeof(array) / sizeof(*array) ?
Кто бы знал...
IMHO, автор хотел выпендриться...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Abyx, Вы писали:
A>скажи им что вместо & надо использовать std::addressof
Зачем?
В смысле зачем говорить?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Классика жанра: вместо array подсунуть указатель на первый элемент.
В случае с sizeof(p)/sizeof(*p) мы получим константу времени компиляции, которая принимает значения от 0 до 8 в зависимости от платформы и типа элементов.
В случае (&p)[1]-&(p[0]) — константа времени исполнения, зависящая от того, какой мусор валяется в памяти рядом с указателем.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Abyx, Вы писали:
A>>скажи им что вместо & надо использовать std::addressof E>Зачем? E>В смысле зачем говорить?
затем что & в обобщенном коде использовать нельзя потому что он может быть перегружен.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, rg45, Вы писали:
R>>Я уверен, Егор это и так знает. Видимо, весь вопрос в волшебном символе &, а точнее в его положении — в одном случае он задает адрес элемента массива, а в другом — адрес всего массива.
E>Именно так. Формально мы ка кбы разыменовываем указатель на место за массивом, но разыменовываем его только для того, что бы преобразовать к адресу нулевого элемента этого несуществующего массива, то есть, фактически,
(typeof(array[0])*)1[&array]
это получение указателя на конец массива. E>Вопрос в том, валидно ли такое недоразыменование?
Спасибо за код. Долго курил, но вопрос остался. А почему тут происходит разименование адреса?
По тойже причине что и
cout << array;
автоматом разименует на 0 элемент?
Если есть желание — найдется 1000 возможностей.
Если нет желания — найдется 1000 причин.
Здравствуйте, k55, Вы писали:
k55>Спасибо за код. Долго курил, но вопрос остался. А почему тут происходит разименование адреса?
Ещё со времён C, для массивов 1[x] тождественно равно *(1+x). ISO/IEC 9899:TC2:
6.5.2.1 Array subscripting
[...]
2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). [...]
Если нет специальных правил для &* (на подобие short-circuit evaluation) — то происходит dereferencing.
Хотя я нашёл вот такие пункты в ISO C:
6.5.3.2 Address and indirection operators
[...]
3. The unary & operator yields the address of its operand. If the operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator. Otherwise, the result is a pointer to the object or function designated by its operand.
4. The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.84)
[...]
84) Thus, &*E is equivalent to E (even if E is a null pointer), and &(E1[E2]) to ((E1)+(E2)). It is always true that if E is a function designator or an lvalue that is a valid operand of the unary & operator, *&E is a function designator or an lvalue equal to E. If *P is an lvalue and T is the name of an object pointer type, *(T)P is an lvalue that has a type compatible with that to which T points.
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
Здравствуйте, Abyx, Вы писали:
A>>>скажи им что вместо & надо использовать std::addressof E>>Зачем? E>>В смысле зачем говорить?
A>затем что & в обобщенном коде использовать нельзя потому что он может быть перегружен.
за такие фокусы (перегрузка &) по рукам надо бы давать.
Здравствуйте, Кодт, Вы писали:
К>В случае с sizeof(p)/sizeof(*p) мы получим константу времени компиляции, которая принимает значения от 0 до 8 в зависимости от платформы и типа элементов.
Гмм. Почему "от 0" ? Поясни, плз.
(То есть, если p — просто указатель, это понятно. Но как будто в треде обсуждается случай, когда p — честный массив. Нет?)
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Насколько легален следующий код: EP>
EP>int main()
EP>{
EP> int x = 0;
EP> auto first = &x;
EP> auto last = first + 1; // legal?
EP> // use as range [first, last)
EP>}
EP>
?
В С++ легален. В С -- не смотрел, но скорее всего тоже легаелен.
Вообще скалярные переменные во всей адресной арифметике везде могут трактоваться как массивы из одного элемента. Есть такой отдельный пункт в стандарте.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Abyx, Вы писали:
E>>В смысле зачем говорить? A>затем что & в обобщенном коде использовать нельзя потому что он может быть перегружен.
Это ответ на вопрос "зачем использовать?", а не на мой...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Вообще скалярные переменные во всей адресной арифметике везде могут трактоваться как массивы из одного элемента. Есть такой отдельный пункт в стандарте.
А какой пункт? Может кто знает/найдёт.
Я помню искал — да видимо keyword'ы не те.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
E>>Вообще скалярные переменные во всей адресной арифметике везде могут трактоваться как массивы из одного элемента. Есть такой отдельный пункт в стандарте.
EP>А какой пункт? Может кто знает/найдёт. EP>Я помню искал — да видимо keyword'ы не те.
5.7 (Additive operators)
...
4. For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the
first element of an array of length one with the type of the object as its element type.
Здравствуйте, Igore, Вы писали:
E>>Спасибо за разъяснения. Я верно понял, что с твоей т. з. тут всё нормуль:
int f( int i)
E>>{
E>> return 1[&i];
E>>}
I>Неверное сравнение, переделаю твой пример I>
I>int f( int i)
I>{
I> return *(&i + 1);
I>}
I>
AFAIK, в С, и в С++, если не намудрить с перегрузкой операторов, выражения
*(1 + &i)
и
1[&i]
ЭКВИВАЛЕНТНЫ...
Тем не менее, всё нормуль, да?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском