|
|
|
Железный канал: «Чугунку про Си» |
|
|
_RAZAAR_
62 EGP
  Рейтинг канала: 2(11) Репутация: -13 Сообщения: 2854 Заблокирован Откуда: РАЗААРЪ - 40Лы от Лаве Зарегистрирован: 15.04.2008
 |
|
Такой пример
Cкрытый текст (кликните здесь для просмотра)
main()
{
float arr[]{ 0.1f, 0.2f, 3.0f };
printf("%i", (int)&arr[2] - (int)&arr[0]);
return 0;
}
|
что не нравится компилятору?
Cкрытый текст (кликните здесь для просмотра)
$ g++ L6_6.cpp -o L6_6
L6_6.cpp: In function ‘int main()’:
L6_6.cpp:6:15: error: cast from ‘float*’ to ‘int’ loses precision [-fpermissive]
6 | printf("%i", (int)&arr[2] - (int)&arr[0]);
| ^~~~~~~~~~~~
L6_6.cpp:6:30: error: cast from ‘float*’ to ‘int’ loses precision [-fpermissive]
6 | printf("%i", (int)&arr[2] - (int)&arr[0]);
| ^~~~~~~~~~~~
|
_________________ Quaere Vērum
------------------------ |
|
|
Grebomet
1466 EGP
      Рейтинг канала: 8(759) Репутация: 261 Сообщения: 4787 Откуда: Питербурх Зарегистрирован: 06.01.2003
 |
|
_RAZAAR_ : |
что не нравится компилятору?
|
Ну он же тебе написал: не нравится, что ты приводишь указатель на флоаты к инту.
Начнем с того, что инт - это число со знаком. Причем на 64-битной машине он частенько бывает 32-битным (привет винде и ее модели памяти).
А указатель - это беззнаковая величина. В 64-битной программе он равен 64 битам (указатель на член класса может быть и больше).
Теперь смотрим, что ты пытаешься сделать:
- берешь указатель на float
- пытаешься его привести к инту.
64 бита беззнаковых не влезают в int, а даже если и влезают, то арифметика с такими интами чревата граблями. Вот тебе компилятор и не дает нагородить граблей.
Собственно, а что ты хотел получить? Размер двух флоатов в памяти? Это можно сделать так:
Код: |
float arr[] {0.1f, 0.2f};
std::cout << sizeof(arr) << std::endl; |
А если тебе надо именно через адресную арифметику, то как-то так:
Код: |
float arr[] {0.1f, 0.2f, 0.3f};
std::cout << ((char*)(&arr[2]) - (char*)(&arr[0])) << std::endl; |
_________________ Классическая ошибка, которую совершают проектировщики абсолютно надежных систем, – недооценка изобретательности клинических идиотов.
Последний раз редактировалось: Grebomet (00:47 19-03-2021), всего редактировалось 1 раз |
|
|
AnrDaemon
864 EGP
        Рейтинг канала: 8(796) Репутация: 37 Сообщения: 12322
Зарегистрирован: 17.10.2004
 |
|
А вы C и C++ не попутали?
_________________ Люблю свободный полёт... :) |
|
|
Grebomet
1466 EGP
      Рейтинг канала: 8(759) Репутация: 261 Сообщения: 4787 Откуда: Питербурх Зарегистрирован: 06.01.2003
 |
|
Тощна! Попутали.
Но сути дела это не меняет - приводить указатель к инту не надо, его надо приводить к указателю.
_________________ Классическая ошибка, которую совершают проектировщики абсолютно надежных систем, – недооценка изобретательности клинических идиотов. |
|
|
_RAZAAR_
62 EGP
  Рейтинг канала: 2(11) Репутация: -13 Сообщения: 2854 Заблокирован Откуда: РАЗААРЪ - 40Лы от Лаве Зарегистрирован: 15.04.2008
 |
|
Grebomet : |
Тощна! Попутали.
Но сути дела это не меняет - приводить указатель к инту не надо, его надо приводить к указателю.
|
Так точно! Чугунок попутал , это C++
Это вопрос из теста выглядел так :
Что выведет на экран приведённая ниже программа
и далее было вообще то буквально вот так:
float arr[]{ 0.1f, 0.2f, 3.0f };
printf("%i", (int)&arr[2] - (int)&arr[0]);
предполагается показать число являющееся разностью указателей адресов элементов массива?
Видимо число байт между начальным адресом элемента 2 и начальным адресом элемента 0?
то-есть размер двух первых элементов массива вместе?
я правильно понимаю?
& -это address pointer?
_________________ Quaere Vērum
------------------------
Последний раз редактировалось: _RAZAAR_ (12:09 20-03-2021), всего редактировалось 1 раз |
|
|
Grebomet
1466 EGP
      Рейтинг канала: 8(759) Репутация: 261 Сообщения: 4787 Откуда: Питербурх Зарегистрирован: 06.01.2003
 |
|
_RAZAAR_ : |
предполагается показать число являющееся разностью указателей адресов элементов массива?
|
Ну видимо да. Других вариантов как-то маловато.
Просто тестирующие, как обычно, спешили и не проверили свой код в реальных условиях.
Настоящие пацаны используют адресную арифметику на указателях и не парятся. Точнее, парятся только размерами типа, на который указывает указатель.
_RAZAAR_ : |
& -это address pointer?
|
Это оператор взятия адреса.
_________________ Классическая ошибка, которую совершают проектировщики абсолютно надежных систем, – недооценка изобретательности клинических идиотов. |
|
|
_RAZAAR_
62 EGP
  Рейтинг канала: 2(11) Репутация: -13 Сообщения: 2854 Заблокирован Откуда: РАЗААРЪ - 40Лы от Лаве Зарегистрирован: 15.04.2008
 |
|
а на это
Cкрытый текст (кликните здесь для просмотра)
#include "stdio.h"
main()
{
float arr[]{ 0.1f, 0.2f, 3.0f };
printf((char*)(&arr[2]) - (char*)(&arr[0]));
}
|
ругает вот так
Cкрытый текст (кликните здесь для просмотра)
$ g++ tst61.cpp -o tst61
tst61.cpp: In function ‘int main()’:
tst61.cpp:6:25: error: invalid conversion from ‘long int’ to ‘const char*’ [-fpermissive]
6 | printf((char*)(&arr[2]) - (char*)(&arr[0]));
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
| |
| long int
In file included from tst61.cpp:1:
/usr/include/stdio.h:200:13: note: initializing argument 1 of ‘int printf(const char*, ...)’
200 | int printf (const char *__restrict, ...)
| ^~~~~~~~~~~~
|
_________________ Quaere Vērum
------------------------ |
|
|
Grebomet
1466 EGP
      Рейтинг канала: 8(759) Репутация: 261 Сообщения: 4787 Откуда: Питербурх Зарегистрирован: 06.01.2003
 |
|
_RAZAAR_ : |
printf((char*)(&arr[2]) - (char*)(&arr[0]));
|
Строку формата забыл: printf("%как", что);
_________________ Классическая ошибка, которую совершают проектировщики абсолютно надежных систем, – недооценка изобретательности клинических идиотов. |
|
|
_RAZAAR_
62 EGP
  Рейтинг канала: 2(11) Репутация: -13 Сообщения: 2854 Заблокирован Откуда: РАЗААРЪ - 40Лы от Лаве Зарегистрирован: 15.04.2008
 |
|
Grebomet : |
_RAZAAR_ : |
printf((char*)(&arr[2]) - (char*)(&arr[0]));
|
Строку формата забыл: printf("%как", что);
|
Да так точно забыл
ответ 8 - тоесть размер двух элементов этого массива
из трёх флоат чисел 8 байт тоесть один элемент занимает 4 байта (32бит)?
или это размер одного элемента 8 байт?
_________________ Quaere Vērum
------------------------ |
|
|
Grebomet
1466 EGP
      Рейтинг канала: 8(759) Репутация: 261 Сообщения: 4787 Откуда: Питербурх Зарегистрирован: 06.01.2003
 |
|
Это размер двух элементов. Флоаты - это 32-битная величина, поэтому 4 байта каждый.
Если точнее, то это расстояние между элементами в массиве. Результат тот же, но семантика сильно другая.
И вообще так лучше не делать, ибо есть прекрасный оператор sizeof, который определяет размер любого типа еще на этапе компиляции. Т.е. достаточно вывести sizeof(float)*2 и никаких массивов заводить не надо.
_________________ Классическая ошибка, которую совершают проектировщики абсолютно надежных систем, – недооценка изобретательности клинических идиотов. |
|
|
_RAZAAR_
62 EGP
  Рейтинг канала: 2(11) Репутация: -13 Сообщения: 2854 Заблокирован Откуда: РАЗААРЪ - 40Лы от Лаве Зарегистрирован: 15.04.2008
 |
|
Grebomet : |
Это размер двух элементов. Флоаты - это 32-битная величина, поэтому 4 байта каждый.
Если точнее, то это расстояние между элементами в массиве. Результат тот же, но семантика сильно другая.
И вообще так лучше не делать, ибо есть прекрасный оператор sizeof, который определяет размер любого типа еще на этапе компиляции. Т.е. достаточно вывести sizeof(float)*2 и никаких массивов заводить не надо.
|
Ну видимо да, просто урок конкретно по массивам был 9 вопросов теста и вот только один както криво афтор составил ну или спецом с подвохом был чтоб тестируемый задумался лучше.
чесно говоря еслиб все вопросы с подвохом были толку наверно от них былобы больше..
и еррор лог компилятора невнятный
cast from ‘float*’ to ‘int’ loses precision
по нему выходит что я пытаюсь конвертировать когда
из этой строчки printf("%i", (int)&arr[2] - (int)&arr[0]); явно видно что никаких конвертаций указывая адрес а не значение элемента быть недолжно.
оно что вообще работать небудет или гдето с синтаксисом чтото?
вот так компилируется
printf("%i", (&arr[2]) - (&arr[0]))
но ответ 2 непонятен, почему эта запись означает что между элементом ноль и элементом два - 2 елемента массива?
их то там два но я же вроде говорю дать мне разность адресов этих илементов? или нет?
адрес элементов массива в конечном итоге разве может быть чемто иным кроме адреса и конкретного типа числа которым он представлен?
_________________ Quaere Vērum
------------------------ |
|
|
Grebomet
1466 EGP
      Рейтинг канала: 8(759) Репутация: 261 Сообщения: 4787 Откуда: Питербурх Зарегистрирован: 06.01.2003
 |
|
_RAZAAR_ : |
и еррор лог компилятора невнятный
cast from ‘float*’ to ‘int’ loses precision
по нему выходит что я пытаюсь конвертировать когда
из этой строчки printf("%i", (int)&arr[2] - (int)&arr[0]); явно видно что никаких конвертаций указывая адрес а не значение элемента быть недолжно.
|
Он ругается на конкретно вот эту конструкцию: (int)&arr[x].
Результат операции arr[x] - это float.
Результат операции &arr[x] - это float*.
А дальше идет попытка привести указатель к инту: (int)&arr[x].
Вот это-то приведение и чревато потерей значимых бит.
_RAZAAR_ : |
оно что вообще работать небудет или гдето с синтаксисом чтото?
|
Работать оно будет, но не во всех случаях. В тех случаях, когда значимые биты адреса перестанут влезать в 31 бит инта, начнутся интересные глюки: отрицательные значения инта или вообще обрезанная половина адреса.
Посему это и сделали ошибкой компиляции.
_RAZAAR_ : |
вот так компилируется
printf("%i", (&arr[2]) - (&arr[0]))
но ответ 2 непонятен, почему эта запись означает что между элементом ноль и элементом два - 2 елемента массива?
|
Именно так, 2 элемента массива. Добро пожаловать в адресную арифметику, сынок.
Когда проводятся вычисления над указателями, компилятор учитывает размер типа, на который указывает указатель:
Код: |
int *pointerToInt = 0;
printf("%p\n", ++pointerToInt ); // выведет 0х0000004, т.к. размер инта - 4.
double *pointerToDouble = 0;
printf("%p\n", ++pointerToDouble ); // выведет 0х0000008, т.к. размер дабла - 8.
char *pointerToChar = 0;
printf("%p\n", ++pointerToChar ); // выведет 0х0000001, т.к. размер чара - 1.
void *pointerToVoid = 0;
printf("%p\n", ++pointerToVoid ); // не скомпилируется. У типа void нет размера,
// посему нельзя узнать, на сколько байт его увеличивать. |
_________________ Классическая ошибка, которую совершают проектировщики абсолютно надежных систем, – недооценка изобретательности клинических идиотов. |
|
|
_RAZAAR_
62 EGP
  Рейтинг канала: 2(11) Репутация: -13 Сообщения: 2854 Заблокирован Откуда: РАЗААРЪ - 40Лы от Лаве Зарегистрирован: 15.04.2008
 |
|
a почему
float *pointerToFloat = 0;
printf("%p\n", ++pointerToFloat ); // размер флоата 32 бита а не 64?
это ограничение?
или double тоже можно использовать как флоат?
_________________ Quaere Vērum
------------------------ |
|
|
Dimaxx
1016 EGP
      Рейтинг канала: 8(898) Репутация: 204 Сообщения: 5811 Откуда: Северодвинск Зарегистрирован: 26.06.2002
 |
|
float одинарная точность (32 бита), double - двойная (64 бита).
В расчетах - конечно можно, во float будет потеря точности.
_________________ "Если мы не покончим с войной, война покончит с нами." Г. Г. Уэллс |
|
|
Grebomet
1466 EGP
      Рейтинг канала: 8(759) Репутация: 261 Сообщения: 4787 Откуда: Питербурх Зарегистрирован: 06.01.2003
 |
|
На всякий случай: в double тоже будет потеря точности, т.к. числа с плавающей точкой приблизительные.
Просто на флоатах оно вылазит раньше и резче, чем на даблах. А еще в интелах математический сопроцессор внутри себя оперирует 80-битными числами, что еще немножко скрывает сию фундаментальную проблему.
_________________ Классическая ошибка, которую совершают проектировщики абсолютно надежных систем, – недооценка изобретательности клинических идиотов. |
|
|
|
|
|
Железный канал: «Чугунку про Си» |
|