powered by simpleCommunicator - 2.0.35     © 2025 Programmizd 02
Форумы / C++ [игнор отключен] [закрыт для гостей] / Перевод на Си
21 сообщений из 46, страница 2 из 2
Перевод на Си
    #40096390
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima T
Если посмотреть на строку в другом контексте
Код: plaintext
1.
2.
3.
int arr[N];
...
*(((int*)arr)+i) = i;


то это будет равносильно
Код: plaintext
1.
arr[i] = i;


никакого UB тут нет и быть не может.
В другом контексте UB нет, но на то он и другой контекст. А у нас контекст не другой.
А по получается что-то вроде:
- `float f; *(int*)&f = 0;` это UB!
- если посмотреть в другом контексте — `int f; *(int*)&f = 0;` — то не UB (подразумевая, что значит и в первом случае не UB)
...
Рейтинг: 0 / 0
Перевод на Си
    #40096394
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry Sibiryakov

a guestв C++ *явно* гарантируется что это не так

В С++ явно гарантируется, что переменная типа "массив" неявно приводится к
указателю на подлежащий тип, имеющий значение адреса первого (то бишь нулевого)
элемента массива. От количества проделанных этих преобразований результат не
меняется.Последнее предложение очень правильно.
arr неявно приводтся к указателю на arr[0], последующее применение (int*) этого результата не меняет, (int*)arr это по-прежнему указатель на arr[0], а не arr[0][0].
...
Рейтинг: 0 / 0
Перевод на Си
    #40096402
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestarr неявно приводтся к указателю на arr[0], последующее применение (int*) этого
результата не меняет, (int*)arr это по-прежнему указатель на arr[0], а не arr[0][0].

Не совсем так. Сначала arr приводится к указателю на int[], потом этот массив
приводится к *int, а потом явно преобразуется в *int (что есть no-op), и уже
потом разыменовывается, получая чистую (законную) ссылку на нулевой элемент
нулевого массива.

Полная операция эквивалентна
Код: sql
1.
2.
3.
int[M]* tmp = &arr[0];
int* tmp2 = &tmp[0];
*tmp2 + i = i;


Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Перевод на Си
    #40096406
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry Sibiryakov

a guestarr неявно приводтся к указателю на arr[0], последующее применение (int*) этого
результата не меняет, (int*)arr это по-прежнему указатель на arr[0], а не arr[0][0].

Не совсем так. Сначала arr приводится к указателю на int[]Приводится к выражению типа int(*)[3] значение которого это «указатель на первый элемент arr»
Dimitry Sibiryakov
, потом этот массив приводится к *int
Потом int(*)[3] никуда неявно не приводится, т.к. тип этого выражения уже не массив и каких-либо других неявных преобразований от int(*)[3] к int* не существует.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096412
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest
White Owl
пропущено...
С чего это вдруг UB? Это как раз стандартная адресная арифметика.
«Стандартная адресная арифметика» это когда имея указатель на arr[0][0] (ведь ожидается что (int*)arr выдаст именно его?), итерируешь от 0 до M. А тут итерируется до N*M, что > M.
Ну и вообще я не знаю в стандарте C гарантий того, что (int*)arr это указатель на arr[0][0] (а в C++ явно гарантируется что это не так).
Нет, arr выдаст указатель на arr[0][0]. А (int*)arr выдаст указатель на int который совпадает с адресом arr[0][0]. Это уже не массив а простой указатель.
Тут итерируется до N*M, потому что я знаю что там есть достаточно памяти для такой операции.
Да, это опасная вещь и да, именно за такие трюки на С и катится большинство бочек.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096416
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestПриводится к выражению типа int(*)[3]

Нет, к массиву указателей оно не приводится. Квадратные скобки заменяются
звёздочками справа налево:
int[X][Y] -> int[X]* -> int*.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Перевод на Си
    #40096419
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096420
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl
a guest
пропущено...
«Стандартная адресная арифметика» это когда имея указатель на arr[0][0] (ведь ожидается что (int*)arr выдаст именно его?), итерируешь от 0 до M. А тут итерируется до N*M, что > M.
Ну и вообще я не знаю в стандарте C гарантий того, что (int*)arr это указатель на arr[0][0] (а в C++ явно гарантируется что это не так).
Нет, arr выдаст указатель на arr[0][0].
Стандарт с этим точно не согласен. Выражения с типом массив неявно преобразуются к указателю на первый элемент, а первый элемент у arr[2][3] это объект с типом arr[3]. А вот что значит каст от int(*)[3] к int* — ХЗ. Если читать стандарт, то он только говорит, что результат такого каста можно кастовать обратно и получить то же значение, что до первого каста (к int*).
Про то, что такой каст выдаст указатель на первый элемент arr[0] — arr[0][0] — не сказано.

White Owl
Да, это опасная вещь и да, именно за такие трюки на С и катится большинство бочек.
Не знаю, что тут подразумевается под «опасной вещью». Либо поведение определено, либо не определено. И тут оно не определено. Как минимум из-за выхода за пределы массива arr[0], если верить что каст к int* выдаст указатель на первый элемент arr[0]. Ну или по консервативным оценкам — (int*)arr + i всегда UB, т.к. стандарт явно не разрешает такого обращения с кастованным указателем, а только разрешает кастить обратно.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096423
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry Sibiryakov

a guestПриводится к выражению типа int(*)[3]

Нет, к массиву указателей оно не приводится. Квадратные скобки заменяются
звёздочками справа налево:
int[X][Y] -> int[X]* -> int*.
int(*)[3] это указатель на массив, массив указателей это int*[3].
...
Рейтинг: 0 / 0
Перевод на Си
    #40096446
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest
White Owl
пропущено...
Нет, arr выдаст указатель на arr[0][0].
Стандарт с этим точно не согласен. Выражения с типом массив неявно преобразуются к указателю на первый элемент, а первый элемент у arr[2][3] это объект с типом arr[3]. А вот что значит каст от int(*)[3] к int* — ХЗ. Если читать стандарт, то он только говорит, что результат такого каста можно кастовать обратно и получить то же значение, что до первого каста (к int*).
Про то, что такой каст выдаст указатель на первый элемент arr[0] — arr[0][0] — не сказано.
Бррр... Зачем ты разбиваешь тип???
Мы делаем принудительное приведение типов. (int*)arr относится к имени arr, а не к его типу. Мы плюем на исходный тип. Как только мы начали делать каст - оно уже совершенно не важно какой там был тип изначально . У нас есть переменная и мы ей назначаем новый тип. Все.
С тем же успехом можно сделать (char*)arr, (void*)arr, (struct CoolStruct*)arr - везде мы получим указатель на соответствующий тип численно равный &arr[0][0].
И да, результат такого каста можно кастовать обратно, если конечно ты знаешь куда.

White Owl
Ну или по консервативным оценкам — (int*)arr + i всегда UB, т.к. стандарт явно не разрешает такого обращения с кастованным указателем, а только разрешает кастить обратно.
Неверно. Это как раз не UB а и есть стандарт адресной арифметики.
(int*)arr + i - эквивалентен (int*)(arr + i). То есть берем реальный тип arr (а это указатель на тип int[N][M]), прибавляем к нему sizeof(int[N][M])*i и полученный адрес принудительно приводим к указателю на int. Запись по такому адресу тебе почти гарантировано даст падение. Это тоже не UB, это адресная арифметика.
А я в примере показывал ((int*)arr) + i - берем адрес, плюем на его оригинальный тип, приводим его к нужному типу, потом уже занимаемся арифметикой.

И да, это опасная вещь если не понимаешь что делаешь или просто опечатался. Но опасная и неопределенная - это два разных прилагательных, не надо их путать :)
...
Рейтинг: 0 / 0
Перевод на Си
    #40096447
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest
int(*)[3] это указатель на массив
Вообще-то, это не указатель на массив, а синтаксическая ошибка.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096469
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl
...
С тем же успехом можно сделать (char*)arr, (void*)arr, (struct CoolStruct*)arr - везде мы получим указатель на соответствующий тип численно равный &arr[0][0].
И да, результат такого каста можно кастовать обратно, если конечно ты знаешь куда.
...

Не совсем, тут есть UB связанное с выравниванием типов, описано где то в стандарте.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096498
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlКак только мы начали делать каст - оно уже совершенно не важно какой там был тип
изначально .

Сишный каст С++ компиляторы преобразуют либо в static_cast, либо в
reinterpret_cast по возможности. static_cast переменной массива в указатель не
пройдёт: они несовместимы, поэтому массив сначала приводится к указателю и
только потом идёт его reinterpret_cast.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Перевод на Си
    #40096507
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl
a guest
int(*)[3] это указатель на массив
Вообще-то, это не указатель на массив, а синтаксическая ошибка.
Если в файле написать только `int` и больше ничего, это тоже будет синтаксической ошибкой.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096543
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl
a guest
пропущено...
Стандарт с этим точно не согласен. Выражения с типом массив неявно преобразуются к указателю на первый элемент, а первый элемент у arr[2][3] это объект с типом arr[3]. А вот что значит каст от int(*)[3] к int* — ХЗ. Если читать стандарт, то он только говорит, что результат такого каста можно кастовать обратно и получить то же значение, что до первого каста (к int*).
Про то, что такой каст выдаст указатель на первый элемент arr[0] — arr[0][0] — не сказано.
Бррр... Зачем ты разбиваешь тип???
Мы делаем принудительное приведение типов. (int*)arr относится к имени arr, а не к его типу. Мы плюем на исходный тип. Как только мы начали делать каст - оно уже совершенно не важно какой там был тип изначально . У нас есть переменная и мы ей назначаем новый тип. Все.
ХЗ что такое "(int*)arr относится к имени arr". arr это lvalue с типом int[2][3]. Когда такое выражение не является операндом sizeof, _Alignof или унарного &, то происходит преобразование массива к указателю. Получается выражение с типом int(*)[3] и значением "указатель на первый элемент соответствующего массива". Так что (int*) применяется к этому неявно преобразованному выражению, а не "имени переменной назначается новый тип".
White Owl
С тем же успехом можно сделать (char*)arr, (void*)arr, (struct CoolStruct*)arr - везде мы получим указатель на соответствующий тип численно равный &arr[0][0].
Ну, в отличие от кастов к другим типам, для каста к (char*) есть отдельное правило, это не просто смена типа выражения.

White Owl
Ну или по консервативным оценкам — (int*)arr + i всегда UB, т.к. стандарт явно не разрешает такого обращения с кастованным указателем, а только разрешает кастить обратно.
Неверно. Это как раз не UB а и есть стандарт адресной арифметики.
(int*)arr + i - эквивалентен (int*)(arr + i).🤦‍♂️
White Owl
То есть берем реальный тип arr (а это указатель на тип int[N][M])
Реальный тип arr это просто int[N][M].
White Owl
И да, это опасная вещь если не понимаешь что делаешь или просто опечатался.
"(int*)arr + i - эквивалентен (int*)(arr + i)" — это первое или второе?
...
Рейтинг: 0 / 0
Перевод на Си
    #40096590
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakov

White OwlКак только мы начали делать каст - оно уже совершенно не важно какой там был тип
изначально .

Сишный каст С++ компиляторы преобразуют либо в static_cast, либо в
reinterpret_cast по возможности. static_cast переменной массива в указатель не
пройдёт: они несовместимы, поэтому массив сначала приводится к указателю и
только потом идёт его reinterpret_cast.
Вот ведь навертели гады!
В принципе то оно понятно зачем и почему такие сложности. Но... с одной стороны, даже это не всегда помогает от самострела. А с другой, при попытке "все-же сделать каст, потому что я знаю что тут можно и нужно", начинаются иногда очень странные пляски с различными типами кастов и в итоге в ногу летит не пуля а целый заряд картечи.
Мне, все же, более простой подход Си нравится больше. Он прост, примитивен, но надежен и полностью предсказуем. А вот вся эта палитра плюсовых кастов... Ух! Излишне усложнено и все равно не дает гарантию от ошибок. Лучше бы вообще запретили каст делать, больше пользы было бы.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096592
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest
ХЗ что такое "(int*)arr относится к имени arr". arr это lvalue
Нет. В рамках данной темы, arr это имя переменной. Это такая сущность имеющая значение только на этапе компилятора и линкера (ну еще остающаяся в дебаг сборке).
Смена типа переменной имеет смысл (и делается) только на этапе компиляции, во время работы у программы есть только адреса памяти к которым обращаются команды типа mov.
lvalue/rvalue здесь совершенно ни причем.
...
Рейтинг: 0 / 0
Перевод на Си
    #40096681
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlВот ведь навертели гады!

Из-за такой вот фигни в ГЦЦ 9 (вроде бы) перестал работать Сишный каст указателя
на одну функцию к другой. В результате результат GetProcAddress() приходится
прогонять через два явных каста.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Перевод на Си
    #40096928
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kasper_,
Код: plaintext
1.
int* *R = reinterpret_cast<int**>( malloc(n*m * sizeof(int) ) );
...
Рейтинг: 0 / 0
Перевод на Си
    #40096930
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что выделение памяти не соответствует, то не моя забота... Пусть ТС додумывает. :)
...
Рейтинг: 0 / 0
Перевод на Си
    #40097659
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl
a guest
ХЗ что такое "(int*)arr относится к имени arr". arr это lvalue
Нет. В рамках данной темы, arr это имя переменной.
Которое, в выражениях, является lvalue. В рамках стандарта. Независимо от темы на SQL.ru.

White Owl
lvalue/rvalue здесь совершенно ни причем.
После такого или такого:
White Owl
a guest
int(*)[3] это указатель на массив
Вообще-то, это не указатель на массив, а синтаксическая ошибка.
и т.п. я всё больше склоняюсь к тому, что ответ на
a guest
White Owl
И да, это опасная вещь если не понимаешь что делаешь или просто опечатался.
"(int*)arr + i - эквивалентен (int*)(arr + i)" — это первое или второе?
это "первое".
...
Рейтинг: 0 / 0
21 сообщений из 46, страница 2 из 2
Форумы / C++ [игнор отключен] [закрыт для гостей] / Перевод на Си
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]