LINUX.ORG.RU

sizeof(conditional operator)

 ,


0

3

Что-то я не пойму, почему в этом коде получается разница между языками

$ cat main.c
#include <stdio.h>
#include <inttypes.h>

int main()
{
	uint8_t a = 0;
	uint8_t b = 1;
	size_t sz = sizeof((uint8_t)0 ? a : b);

	printf("sz=%u\n", sz);

	return 0;
}

$ gcc main.c
$ ./a.out 
sz=4
$ g++ main.c
$ ./a.out 
sz=1


Проверял с gcc, clang, MS VC разных версий, варьировал стандарты.
Компилятор C++ вычисляет размер правильно. Наверное большинство людей такой результат и ожидало бы. Чего ж тогда сишному не нравится? Откуда четвёрка, даже на 64-х разрядной машине? Гуру, просветите.



Последнее исправление: gogi (всего исправлений: 1)
Ответ на: комментарий от gogi

MinGW с gcc 5.1.0.

Хотя если компилить, как для студии, всё ок.

Deleted
()
Последнее исправление: merhalak (всего исправлений: 1)

Откуда четвёрка, даже на 64-х разрядной машине

Скорее всего тут участвует integer promotion, а плафторма у тебя LP64, как у всех, так что sizeof(int) == 4.

Почему вообще сабж — не знаю.

arturpub ★★
()

Побоюсь показаться КО, но потому что в C второй и третий аргумент тернарного оператора привелись к int, а в C++ — нет.

Почему в C++ нет — не знаю.

t184256 ★★★★★
()
Последнее исправление: t184256 (всего исправлений: 1)
Ответ на: комментарий от arturpub
#include <stdio.h>
#include <stdint.h>

#define print(format, ...) printf(format "\n", ##__VA_ARGS__)

int
main(int argc, char *argv[])
{
    uint8_t x, y;

    print("%zu", sizeof(void *));
    print("%zu", sizeof(int));
    print("%zu", sizeof(x));
    print("%zu", sizeof(argc > 1 ? x : y));
    print("%zu", sizeof(x + 1));
    print("%zu", sizeof(x + y));

    return 0;
}
$ cc -std=c99 -Wall x.c
$ ./a.out
8
4
1
4
4
4
arturpub ★★
()
Ответ на: комментарий от t184256

Почему в C++ нет — не знаю.

Потому что в C++ результат тернарного выражения — lvalue. Если поменять тип a или b на int8_t, то есть того же размера, но не совпадающий, включатся правила приведения, размер будет 4.

i-rinat ★★★★★
()

Потому что C ≠ C++. И вообще баян.

// cc -o sizeof_c sizeof.c
// c++ -o sizeof_cc sizeof.c

#include <stdio.h>

char *
iam()
{
	switch (sizeof('a')) {
	case 4:
		return "C";
	case 1:
		return "C++";
	default:
		return "whatever";
	}
}

int
main()
{
	printf("I am %s\n", iam());
	return 0;
}
beastie ★★★★★
()
Ответ на: комментарий от i-rinat

в C++ результат тернарного выражения — lvalue

А, точно. Помню на сишке как-то приходилось *(x ? &y : &z) = 💩 писать :)

arturpub ★★
()

Reading Comprehension IV

6.5.15/5 Conditional operator

If both the second and third operands have arithmetic type, the result type that would be determined by the usual arithmetic conversions, were they applied to those two operands, is the type of the result. <...>

6.3.1.8/1 Usual arithmetic conversions

<...> First, if the corresponding real type of either operand is long double, <...>

Otherwise, the integer promotions are performed on both operands. <...>

6.3.1.1/2 Boolean, characters, and integers

The following may be used in an expression wherever an int or unsigned int may be used:

  • An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of int and unsigned int.
  • <...>

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. <...>

Так что t184256 прав.

Для определения типа результата оба операнда приводятся друг к другу, что подразумевает расширение до инта. В Си++, видимо, просто более строгие правила преобразования типов.

ilammy ★★★
()
Ответ на: комментарий от ilammy

Исчерпывающе, добавить нечего пожалуй. Всё по стандарту.

gogi
() автор топика
Ответ на: комментарий от t184256

побоюсь показаться еще большим КО, но t\d{6} прав или почти прав. в С++ ?: перегружаема и шаблонна, и имеет тип boolxTxT->T, а в C это арифметическая операция, и результат возвращается соотвественно размерности платформы

MyTrooName ★★★★★
()
Ответ на: комментарий от t184256

в C второй и третий аргумент тернарного оператора привелись к int

Это не по стандарту. В сишке тип тернарного выражения равен наибольшему расширению типов a и b, а там же uint8_t.

iVS ★★★★★
()
Последнее исправление: iVS (всего исправлений: 1)
Ответ на: комментарий от ilammy

Для определения типа результата оба операнда приводятся друг к другу, что подразумевает расширение до инта.

Жесть. Как теперь жить?

iVS ★★★★★
()

Мне одному кажется, что использовать sizeof как обычную функцию это идиотизм? Неужели лень написать

0 ? sizeof (a) : sizeof (b)
.

anonymous
()
Ответ на: комментарий от anonymous

Это синтетический тест для воспроизведения проблемы. В реальном коде мне надо было кое-что другое.

gogi
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.