Форум программистов, компьютерный форум CyberForum.ru

Нюансы использования оператора sizeof() - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.61
thick_int
Заблокирован
21.11.2011, 11:53     Нюансы использования оператора sizeof() #1
Пусть T - это некоторой тип, а t - это переменная типа T.
Может ли когда-нибудь выражение
C++
1
sizeof(T) != sizeof t
оказаться верным?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.11.2011, 11:53     Нюансы использования оператора sizeof()
Посмотрите здесь:

C++ Нюансы использования операторов new/delete в деструкторах
C++ Нюансы использования абстрактных базовых классов (класс Shape)
C++ Объяснить разницу между массивом типа char и строкой в стиле Си (нюансы использования нуль-терминатора)
C++ Раздельная компиляция (нюансы использования заголовочных файлов и файлов реализации)
C++ Нюансы использования исключений: объяснить причины и способы устранения ошибки
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
thick_int
Заблокирован
21.11.2011, 13:31  [ТС]     Нюансы использования оператора sizeof() #21
Цитата Сообщение от Jupiter Посмотреть сообщение
по умолчанию то что в двойных кавычках имеет тип const char[](потому что мы не может написать вот так
C++
1
"TestStr" = ...
), а символьный массив а просто инициализируется строковым литералом
После чего мы уже ничего не можем записывать в этот массив (во всяком случае простым присваиванием типа
C++
1
a = "Best"
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Jupiter
Каратель
Эксперт C++
6543 / 3963 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
21.11.2011, 13:34     Нюансы использования оператора sizeof() #22
Цитата Сообщение от thick_int Посмотреть сообщение
После чего мы уже ничего не можем записывать в этот массив (во всяком случае простым присваиванием типа
присваивать строки нельзя, их можно только копировать, присваивать можно указатели на строковые литералы
Сыроежка
Заблокирован
21.11.2011, 13:57     Нюансы использования оператора sizeof() #23
Цитата Сообщение от thick_int Посмотреть сообщение
Пусть T - это некоторой тип, а t - это переменная типа T.
Может ли когда-нибудь выражение
C++
1
sizeof(T) != sizeof t
оказаться верным?
Нет, не может! Память любому объекту всегда выдеяется на основании его типа. То есть, несколько косноязыча говоря, память выделяется типу, а затем предоставляется в распоряжение объекта.

Другое дело, что не всегда в выражениях можно заменить sizeof( T ) на siizeof( t ), хотя формально их значения равны.

Например,

C++
1
2
void f( int a, int b = sizeof( a ) );     //  Ошибка: нельзя использовать sizeof( a )
void f( int a, int b = sizeof( int ) );   //  Корректно: значение по умолчанию для параметра b = sizeof( int )
accept
4838 / 3237 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
21.11.2011, 22:28     Нюансы использования оператора sizeof() #24
Цитата Сообщение от thick_int
После чего мы уже ничего не можем записывать в этот массив
сделай a[0] = 'b';
thick_int
Заблокирован
21.11.2011, 23:27  [ТС]     Нюансы использования оператора sizeof() #25
Цитата Сообщение от accept Посмотреть сообщение
сделай a[0] = 'b';
Нет ну так то понятно. Однако и здесь не все так просто.
Например, вот такой вариант
C++
1
2
3
4
char str[5] = "Test";
cout << str << endl;
str[0] = 'B';
cout << str << endl;
проходит

И такой вариант
C++
1
2
3
4
char str[] = "Test";
cout << str << endl;
str[0] = 'B';
cout << str << endl;
тоже проходит

А вот такой уже не проходит
C++
1
2
3
4
char* str = "Test";
cout << str << endl;
str[0] = 'B'; //Здесь ошибка
cout << str << endl;
То есть в данном случае традиционная ассоциация между указателями и массивами слегка подпорчена.
Сыроежка
Заблокирован
21.11.2011, 23:51     Нюансы использования оператора sizeof() #26
Цитата Сообщение от thick_int Посмотреть сообщение
Нет ну так то понятно. Однако и здесь не все так просто.
Например, вот такой вариант
C++
1
2
3
4
char str[5] = "Test";
cout << str << endl;
str[0] = 'B';
cout << str << endl;
проходит

И такой вариант
C++
1
2
3
4
char str[] = "Test";
cout << str << endl;
str[0] = 'B';
cout << str << endl;
тоже проходит

А вот такой уже не проходит
C++
1
2
3
4
char* str = "Test";
cout << str << endl;
str[0] = 'B'; //Здесь ошибка
cout << str << endl;
То есть в данном случае традиционная ассоциация между указателями и массивами слегка подпорчена.
Указатель - это не массив. Просто имеется неявное преобразование в выражениях или при передачи массива в качестве аргумента функции имени массива в указатель на его первый элемент.

В последнем вашем примере, вы объявляете указатель, который указывает на строковый литерал "Test". В С++ строковый литерал имеет тип const char[], поэтому и указатель правильно объявлять как

C++
1
const char *str = "Test";
Просто для совместимости с кодом языка С стандарт С++ разрешает не писать квалификатор const для таких указателей, хотя предупреждает, что в будущем такое послабление может быть отменено стандартом С++, а потому такое объявление указателя без const компиляторами будет рассматриваться как ошибка.
thick_int
Заблокирован
21.11.2011, 23:59  [ТС]     Нюансы использования оператора sizeof() #27
А вот тут я тоже Вас хочу разочаровать.
Тот код, который вроде как не срабатывает
C++
1
2
3
4
char* str = "Test";
cout << str << endl;
str[0] = 'B'; //Здесь ошибка
cout << str << endl;
на самом деле оказывается вполне работоспособным, если его оформить в виде отдельной функции и передать ей соответствующий указатель.
А вот если, объявить переменную str с типом const char*, то тут уже компилятор возмутится на передачу константного объекта в неконстантный параметр.
Ну в смысле, когда Вы менять будете.
Так что здесь иеются свои тонкости.
Сыроежка
Заблокирован
22.11.2011, 00:05     Нюансы использования оператора sizeof() #28
Цитата Сообщение от thick_int Посмотреть сообщение
А вот тут я тоже Вас хочу разочаровать.
Тот код, который вроде как не срабатывает
C++
1
2
3
4
char* str = "Test";
cout << str << endl;
str[0] = 'B'; //Здесь ошибка
cout << str << endl;
на самом деле оказывается вполне работоспособным, если его оформить в виде отдельной функции и передать ей соответствующий указатель.
А вот если, объявить переменную str с типом const char*, то тут уже компилятор возмутится на передачу константного объекта в неконстантный параметр.
Так что здесь иеются свои тонкости.
Вы меня не разочаровали, потому что в отличии от вас я знаю стандарт С++!

Компилятору разрешается литералы помещать в память только для чтения. А потому если вы попытаетесь его изменить, то ваша программа может завершиться аварийно.
То есть попытка изменения строкового литерала согласно стандарту означает неопределенное поведение программы. Что это значит? Что, например, в Windows у вас программа завершится аварийно. А где-то в старом MS-DOS может и пройти такой фокус. Так что никаких "тонкостей" нет. Тонкости состоят лишь в том, что вы с первого раза не поняли, что я первоначально написал. Вот и вся "тонкость".
accept
4838 / 3237 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
22.11.2011, 01:03     Нюансы использования оператора sizeof() #29
Цитата Сообщение от thick_int
А вот такой уже не проходит
C++
1
2
3
4
char* str = "Test";
cout << str << endl;
str[0] = 'B'; //Здесь ошибка
cout << str << endl;
а с чего ему проходить ? указатель на символ и массив символов - разные вещи
в случае с указателем в него записывается один адрес одного символа, даже сам символ в него не записывается, только адрес
(адрес первого символа в цепочке символов, завершающейся нуль-символом, которая находится где угодно в памяти)

вот такая проходит
C++
1
2
3
4
5
char a[] = "Test";
char *str = a;
cout << str << endl;
str[0] = 'B'; //Здесь не ошибка
cout << str << endl;
igelstein
0 / 0 / 0
Регистрация: 14.01.2016
Сообщений: 4
14.01.2016, 19:03     Нюансы использования оператора sizeof() #30
Объясните нубу по поводу sizeof. В литературе данный оператор представлен как средство для обеспечения машинонезависимости, при этом указано, что оператор выполняется на этапе компиляции. Но если я получил ехе-файл на одной машине, а запустил на другой, то каким образом sizeof определит значения типов на новой машине? разве компиляция выполняется при каждом запуске ехе-файла?
hoggy
5230 / 2121 / 404
Регистрация: 15.11.2014
Сообщений: 4,812
Завершенные тесты: 1
14.01.2016, 20:12     Нюансы использования оператора sizeof() #31
Цитата Сообщение от igelstein Посмотреть сообщение
Объясните нубу по поводу sizeof. В литературе данный оператор представлен как средство для обеспечения машинонезависимости, при этом указано, что оператор выполняется на этапе компиляции. Но если я получил ехе-файл на одной машине, а запустил на другой, то каким образом sizeof определит значения типов на новой машине? разве компиляция выполняется при каждом запуске ехе-файла?
что бы получить exe, нужно сначала скомпилировать программу.
после компиляции уже не существует ни sizeof, ни с++.

есть только машинный код - цепочка циферок,
которые понимает центральный процессор.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,919
Записей в блоге: 2
Завершенные тесты: 1
14.01.2016, 20:15     Нюансы использования оператора sizeof() #32
Цитата Сообщение от igelstein Посмотреть сообщение
Но если я получил ехе-файл на одной машине, а запустил на другой, то каким образом sizeof определит значения типов на новой машине?
Никак. Ваша программа скомпилирована под определенную архитектуру.
igelstein
0 / 0 / 0
Регистрация: 14.01.2016
Сообщений: 4
14.01.2016, 20:25     Нюансы использования оператора sizeof() #33
Цитата Сообщение от hoggy Посмотреть сообщение
что бы получить exe, нужно сначала скомпилировать программу.
после компиляции уже не существует ни sizeof, ни с++.
Цитата Сообщение от Croessmah Посмотреть сообщение
Никак. Ваша программа скомпилирована под определенную архитектуру.
Вот и я так же рассуждал. А причём тогда здесь машинонезависимость? Или это относится к компиляции в промежуточные "форматы"? когда программа "докомпелируется" при/перед выполнением в виртуальной среде или т.п.?
hoggy
5230 / 2121 / 404
Регистрация: 15.11.2014
Сообщений: 4,812
Завершенные тесты: 1
14.01.2016, 21:20     Нюансы использования оператора sizeof() #34
Цитата Сообщение от igelstein Посмотреть сообщение
Вот и я так же рассуждал. А причём тогда здесь машинонезависимость?
при том, что программа компилируется конкретным компилятором под конкретную платформу.
а не в сферическом вакууме.

на разных платформах размеры типов могут быть разными.
но в исходном коде вам эти различия учитывать не нужно.

sizeof всегда возвращает правильный размер
независмо от платформы и её нюансов.
igelstein
0 / 0 / 0
Регистрация: 14.01.2016
Сообщений: 4
14.01.2016, 21:56     Нюансы использования оператора sizeof() #35
hoggy, т.е. имеется в виду, что трансляция/компиляция проги на языке С++ будет давать идентичные результаты на разных машинах, но гарантированно работоспособными полученные/скомпилированные программы будут только на этих же машинах?
hoggy
5230 / 2121 / 404
Регистрация: 15.11.2014
Сообщений: 4,812
Завершенные тесты: 1
14.01.2016, 22:42     Нюансы использования оператора sizeof() #36
Цитата Сообщение от igelstein Посмотреть сообщение
имеется в виду, что трансляция/компиляция проги на языке С++ будет давать идентичные результаты на разных машинах
нет.
результаты будут соотвествовать машинам
на которых осуществлялась сборка.
и могут не сооотвествовать другим машинам.
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16843 / 5264 / 323
Регистрация: 30.03.2009
Сообщений: 14,159
Записей в блоге: 26
15.01.2016, 10:12     Нюансы использования оператора sizeof() #37
Цитата Сообщение от igelstein Посмотреть сообщение
Объясните нубу по поводу sizeof. В литературе данный оператор представлен как средство для обеспечения машинонезависимости, при этом указано, что оператор выполняется на этапе компиляции. Но если я получил ехе-файл на одной машине, а запустил на другой, то каким образом sizeof определит значения типов на новой машине? разве компиляция выполняется при каждом запуске ехе-файла?
В данном случае под словом "машиннонезависимость" на самом деле имеется в виду что-то типа "программные соглашения по размерам типов на конкретной платформе". Допустим, нужно обнулить массив. Если писать так:

C
int a[100];
memset (a, 0, 400);
то такой код будет работать правильно (т.е. по задумке афтора) только на тех платформах (точнее, компиляторах), где размер int'а равен 4 байтам. А если написать вот так:

C
int a[100];
memset (a, 0, 100 * sizeof(int));
то код будет работать корректно на любой платформе, на которой мы скомпилируем данный пример
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,919
Записей в блоге: 2
Завершенные тесты: 1
15.01.2016, 10:17     Нюансы использования оператора sizeof() #38
Evg, другими словами кроссплатформенность на уровне компиляции (исходного кода).
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16843 / 5264 / 323
Регистрация: 30.03.2009
Сообщений: 14,159
Записей в блоге: 26
15.01.2016, 12:03     Нюансы использования оператора sizeof() #39
Цитата Сообщение от Croessmah Посмотреть сообщение
кроссплатформенность
Кроссплатформенность - слишком широкое понятие. Тут даже не тянет на одну из её составляющих. Даже в рамках одного приложения на одной архитектуре полезно использовать sizeof. Типа того что

C
typedef int ttt;
ttt *p = malloc (n * sizeof (ttt));
или

C
typedef int ttt;
ttt *p = malloc (n * sizeof (*p));
Т.е. завели typedef, и работаем с ним через sizeof, чтобы не держать в голове реальный тип. Не говоря уж о том, что базовый тип typedef'а в какой-то момент может измениться

Добавлено через 2 минуты
Цитата Сообщение от thick_int Посмотреть сообщение
Пусть T - это некоторой тип, а t - это переменная типа T.
Может ли когда-нибудь выражение
sizeof(T) != sizeof t
оказаться верным?
Смотря что тут подразумевается под T: его синтаксическое написание или реальный тип переменной

C
#include <stdio.h>
 
void foo (int a[100])
{
  int b[100];
 
  printf ("%d\n", (int) sizeof(a));
  printf ("%d\n", (int) sizeof(b));
}
 
int main (void)
{
  foo (NULL);
  return 0;
}
Код
$ gcc t.c
$ ./a.out
4
400
Добавлено через 5 минут
Ну или для удобства вот так:

C
#include <stdio.h>
 
typedef int T[100];
 
void foo (T a)
{
  T b;
 
  printf ("%d\n", (int) sizeof(T));
  printf ("%d\n", (int) sizeof(a));
  printf ("%d\n", (int) sizeof(b));
}
 
int main (void)
{
  foo (NULL);
  return 0;
}
Код
$ gcc t.c
$ ./a.out
400
4
400
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.01.2016, 15:14     Нюансы использования оператора sizeof()
Еще ссылки по теме:

C++ Как корректно прервать цикл? (нюансы использования циклов, операторов ветвления и оператора break)
C++ Нюансы синтаксиса и тонкости использования указателей и массивов
Нюансы использования динамических массивов в качестве данных-членов в классах C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
igelstein
0 / 0 / 0
Регистрация: 14.01.2016
Сообщений: 4
15.01.2016, 15:14     Нюансы использования оператора sizeof() #40
Спасибо всем тем, кто помог советом и ответом. Свой затуп осознал
Yandex
Объявления
15.01.2016, 15:14     Нюансы использования оператора sizeof()
Ответ Создать тему
Опции темы

Текущее время: 23:40. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru