|
Перевод на Си
|
|||
---|---|---|---|
#18+
Dima T Если посмотреть на строку в другом контексте Код: plaintext 1. 2. 3.
то это будет равносильно Код: plaintext 1.
никакого UB тут нет и быть не может. А по получается что-то вроде: - `float f; *(int*)&f = 0;` это UB! - если посмотреть в другом контексте — `int f; *(int*)&f = 0;` — то не UB (подразумевая, что значит и в первом случае не UB) ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 15:51 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
Dimitry Sibiryakov a guestв C++ *явно* гарантируется что это не так В С++ явно гарантируется, что переменная типа "массив" неявно приводится к указателю на подлежащий тип, имеющий значение адреса первого (то бишь нулевого) элемента массива. От количества проделанных этих преобразований результат не меняется.Последнее предложение очень правильно. arr неявно приводтся к указателю на arr[0], последующее применение (int*) этого результата не меняет, (int*)arr это по-прежнему указатель на arr[0], а не arr[0][0]. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 15:54 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
a guestarr неявно приводтся к указателю на arr[0], последующее применение (int*) этого результата не меняет, (int*)arr это по-прежнему указатель на arr[0], а не arr[0][0]. Не совсем так. Сначала arr приводится к указателю на int[], потом этот массив приводится к *int, а потом явно преобразуется в *int (что есть no-op), и уже потом разыменовывается, получая чистую (законную) ссылку на нулевой элемент нулевого массива. Полная операция эквивалентна Код: sql 1. 2. 3.
Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:03 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
Dimitry Sibiryakov a guestarr неявно приводтся к указателю на arr[0], последующее применение (int*) этого результата не меняет, (int*)arr это по-прежнему указатель на arr[0], а не arr[0][0]. Не совсем так. Сначала arr приводится к указателю на int[]Приводится к выражению типа int(*)[3] значение которого это «указатель на первый элемент arr» Dimitry Sibiryakov , потом этот массив приводится к *int ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:11 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
a guest White Owl пропущено... С чего это вдруг UB? Это как раз стандартная адресная арифметика. Ну и вообще я не знаю в стандарте C гарантий того, что (int*)arr это указатель на arr[0][0] (а в C++ явно гарантируется что это не так). Тут итерируется до N*M, потому что я знаю что там есть достаточно памяти для такой операции. Да, это опасная вещь и да, именно за такие трюки на С и катится большинство бочек. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:16 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
a guestПриводится к выражению типа int(*)[3] Нет, к массиву указателей оно не приводится. Квадратные скобки заменяются звёздочками справа налево: int[X][Y] -> int[X]* -> int*. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:22 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
a guest В другом контексте UB нет, но на то он и другой контекст. А у нас контекст не другой. А по получается что-то вроде: - `float f; *(int*)&f = 0;` это UB! - если посмотреть в другом контексте — `int f; *(int*)&f = 0;` — то не UB (подразумевая, что значит и в первом случае не UB) А вот тут ты не прав. Во втором примере ты просто берешь указатель на переменную, потом разименовываешь его получая на выходе ту же самую переменную. Так делать действительно можно и это не UB. А вот в первом, у тебя происходит смена типа для не взаимозаменяемых типов, причем как закодирован float в памяти зависит в первую очередь от железа, как там процессор хранит float (IEEE 754 это всего-лишь один из стандартов). То есть на разных процессорах, в разных компиляторах результат операции float f; *(int*)&f = 0; может быть разным, поэтому это действительно UB. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:26 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
White Owl a guest пропущено... «Стандартная адресная арифметика» это когда имея указатель на arr[0][0] (ведь ожидается что (int*)arr выдаст именно его?), итерируешь от 0 до M. А тут итерируется до N*M, что > M. Ну и вообще я не знаю в стандарте C гарантий того, что (int*)arr это указатель на arr[0][0] (а в C++ явно гарантируется что это не так). Про то, что такой каст выдаст указатель на первый элемент arr[0] — arr[0][0] — не сказано. White Owl Да, это опасная вещь и да, именно за такие трюки на С и катится большинство бочек. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:27 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
Dimitry Sibiryakov a guestПриводится к выражению типа int(*)[3] Нет, к массиву указателей оно не приводится. Квадратные скобки заменяются звёздочками справа налево: int[X][Y] -> int[X]* -> int*. int(*)[3] это указатель на массив, массив указателей это int*[3]. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:28 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
a guest White Owl пропущено... Нет, arr выдаст указатель на arr[0][0]. Про то, что такой каст выдаст указатель на первый элемент arr[0] — arr[0][0] — не сказано. Мы делаем принудительное приведение типов. (int*)arr относится к имени arr, а не к его типу. Мы плюем на исходный тип. Как только мы начали делать каст - оно уже совершенно не важно какой там был тип изначально . У нас есть переменная и мы ей назначаем новый тип. Все. С тем же успехом можно сделать (char*)arr, (void*)arr, (struct CoolStruct*)arr - везде мы получим указатель на соответствующий тип численно равный &arr[0][0]. И да, результат такого каста можно кастовать обратно, если конечно ты знаешь куда. White Owl Ну или по консервативным оценкам — (int*)arr + i всегда UB, т.к. стандарт явно не разрешает такого обращения с кастованным указателем, а только разрешает кастить обратно. (int*)arr + i - эквивалентен (int*)(arr + i). То есть берем реальный тип arr (а это указатель на тип int[N][M]), прибавляем к нему sizeof(int[N][M])*i и полученный адрес принудительно приводим к указателю на int. Запись по такому адресу тебе почти гарантировано даст падение. Это тоже не UB, это адресная арифметика. А я в примере показывал ((int*)arr) + i - берем адрес, плюем на его оригинальный тип, приводим его к нужному типу, потом уже занимаемся арифметикой. И да, это опасная вещь если не понимаешь что делаешь или просто опечатался. Но опасная и неопределенная - это два разных прилагательных, не надо их путать :) ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 16:58 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
a guest int(*)[3] это указатель на массив ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 17:00 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
White Owl ... С тем же успехом можно сделать (char*)arr, (void*)arr, (struct CoolStruct*)arr - везде мы получим указатель на соответствующий тип численно равный &arr[0][0]. И да, результат такого каста можно кастовать обратно, если конечно ты знаешь куда. ... Не совсем, тут есть UB связанное с выравниванием типов, описано где то в стандарте. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 17:25 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
White OwlКак только мы начали делать каст - оно уже совершенно не важно какой там был тип изначально . Сишный каст С++ компиляторы преобразуют либо в static_cast, либо в reinterpret_cast по возможности. static_cast переменной массива в указатель не пройдёт: они несовместимы, поэтому массив сначала приводится к указателю и только потом идёт его reinterpret_cast. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 17:59 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
White Owl a guest int(*)[3] это указатель на массив ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 18:14 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
White Owl a guest пропущено... Стандарт с этим точно не согласен. Выражения с типом массив неявно преобразуются к указателю на первый элемент, а первый элемент у arr[2][3] это объект с типом arr[3]. А вот что значит каст от int(*)[3] к int* — ХЗ. Если читать стандарт, то он только говорит, что результат такого каста можно кастовать обратно и получить то же значение, что до первого каста (к int*). Про то, что такой каст выдаст указатель на первый элемент arr[0] — arr[0][0] — не сказано. Мы делаем принудительное приведение типов. (int*)arr относится к имени arr, а не к его типу. Мы плюем на исходный тип. Как только мы начали делать каст - оно уже совершенно не важно какой там был тип изначально . У нас есть переменная и мы ей назначаем новый тип. Все. White Owl С тем же успехом можно сделать (char*)arr, (void*)arr, (struct CoolStruct*)arr - везде мы получим указатель на соответствующий тип численно равный &arr[0][0]. White Owl Ну или по консервативным оценкам — (int*)arr + i всегда UB, т.к. стандарт явно не разрешает такого обращения с кастованным указателем, а только разрешает кастить обратно. (int*)arr + i - эквивалентен (int*)(arr + i).🤦♂️ White Owl То есть берем реальный тип arr (а это указатель на тип int[N][M]) White Owl И да, это опасная вещь если не понимаешь что делаешь или просто опечатался. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 20:04 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
Dimitry Sibiryakov White OwlКак только мы начали делать каст - оно уже совершенно не важно какой там был тип изначально . Сишный каст С++ компиляторы преобразуют либо в static_cast, либо в reinterpret_cast по возможности. static_cast переменной массива в указатель не пройдёт: они несовместимы, поэтому массив сначала приводится к указателю и только потом идёт его reinterpret_cast. Вот ведь навертели гады! В принципе то оно понятно зачем и почему такие сложности. Но... с одной стороны, даже это не всегда помогает от самострела. А с другой, при попытке "все-же сделать каст, потому что я знаю что тут можно и нужно", начинаются иногда очень странные пляски с различными типами кастов и в итоге в ногу летит не пуля а целый заряд картечи. Мне, все же, более простой подход Си нравится больше. Он прост, примитивен, но надежен и полностью предсказуем. А вот вся эта палитра плюсовых кастов... Ух! Излишне усложнено и все равно не дает гарантию от ошибок. Лучше бы вообще запретили каст делать, больше пользы было бы. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 05:26 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
a guest ХЗ что такое "(int*)arr относится к имени arr". arr это lvalue Смена типа переменной имеет смысл (и делается) только на этапе компиляции, во время работы у программы есть только адреса памяти к которым обращаются команды типа mov. lvalue/rvalue здесь совершенно ни причем. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 05:33 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
White OwlВот ведь навертели гады! Из-за такой вот фигни в ГЦЦ 9 (вроде бы) перестал работать Сишный каст указателя на одну функцию к другой. В результате результат GetProcAddress() приходится прогонять через два явных каста. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 12:44 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
kasper_, Код: plaintext 1.
... |
|||
:
Нравится:
Не нравится:
|
|||
11.09.2021, 21:52 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
Что выделение памяти не соответствует, то не моя забота... Пусть ТС додумывает. :) ... |
|||
:
Нравится:
Не нравится:
|
|||
11.09.2021, 22:32 |
|
Перевод на Си
|
|||
---|---|---|---|
#18+
White Owl a guest ХЗ что такое "(int*)arr относится к имени arr". arr это lvalue White Owl lvalue/rvalue здесь совершенно ни причем. White Owl a guest int(*)[3] это указатель на массив a guest White Owl И да, это опасная вещь если не понимаешь что делаешь или просто опечатался. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.09.2021, 20:08 |
|
|
start [/forum/topic.php?fid=57&msg=40096447&tid=2017171]: |
0ms |
get settings: |
11ms |
get forum list: |
13ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
41ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
60ms |
get tp. blocked users: |
1ms |
others: | 15ms |
total: | 160ms |
0 / 0 |