LINUX.ORG.RU

4.2 на хабре

 ,


0

4

В статье http://habrahabr.ru/post/267239/ автор наезжает на общепринятый в C и C++ трюк с использованием union, утверждая, что стандарт такое использование запрещает:

стандарт считает, что читаться всегда должно только то значение, которое было записано ранее. Запись одного типа с последующим чтением другого — undefined behavior.

Есть кто с учёткой на хабре, напишите ему, что он нехороший человек. Цитата из стандарта:

If a standard-layout union contains two or more standard-layout structs that share a common initial sequence, and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them. Two standard-layout structs share a common initial sequence if corresponding members have layout-compatible types and either neither member is a bit-field or both are bit-fields with the same width for a sequence of one or more initial members.

Нельзя же так на популярном ресурсе делать, могут читать дети.

★★★★
Ответ на: комментарий от i-rinat

Всё правильно. sizeof же не обязательно размер в байтах возвращает.

тоесть то что микрософтовский компилятор для проекта в UTF8 sizeof(char) вернет 2 либо 4 либо 16 (в то время как без утф будет 1)-по твоему не нормально?

а вот микрософт так не считает

sup9999
()
Ответ на: C99 от anonymous

Одна из цитат — из cpp, вторая — из c99. Ничего?

x3al ★★★★★
()
Ответ на: C99 от anonymous

Ой, ты меня поймал.

Проблема тут в том, что именно понимают под байтом. Обычно все считают байтом группу из восьми бит. А в стандарте написано

addressable unit of data storage large enough to hold any member of the basic character set of the execution environment

Ну то есть это может быть и 8, и 16, и 36 бит.

i-rinat ★★★★★
()
Ответ на: комментарий от x3al

Ничего, в C++ так же:

The sizeof operator yields the number of bytes in the object representation of its operand

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

микрософтовский компилятор для проекта в UTF8 sizeof(char) вернет 2 либо 4 либо 16

Не char, а TCHAR и точно не utf-8.

Gvidon ★★★★
() автор топика
Ответ на: комментарий от i-rinat

Обычно все считают байтом группу из восьми бит

Правильные сишники так не считают :D

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

В <climits>: CHAR_BIT - number of bits in byte

Ещё, вроде как, байт не может быть меньше 8 бит, но может быть больше (UPD: точно - The C standard requires that the integral data type char must hold at least 256 different values, and is represented by at least eight bits (clause 5.2.4.2.1)).

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

Правильные сишники

Большинство не видело ничего кроме x86. Я, в общем-то, тоже. На виденных мной ARM'ах и MIPS'ах char'ы тоже были по восемь бит. Знания о том, что они бывают других размеров пригодились только для сообщений на ЛОРе. Польза от них сомнительна.

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

Всё так, но имхо лучше мыслить в терминах стандарта. Хреново тут что сишные термины не очень хорошо согласуются с общепринятыми.

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

Хватит гуглить, скачай уже себе драфт стандарта и воюй на здоровье :)

Зачем сразу «воюй»? Я тут просто пополняю запас ненужных знаний, про которые, тем не менее, иногда любят спрашивать разные дрочеры. Ибо, как ты правильно заметил:

На виденных мной ARM'ах и MIPS'ах char'ы тоже были по восемь бит. Знания о том, что они бывают других размеров пригодились только для сообщений на ЛОРе. Польза от них сомнительна.

asaw ★★★★★
()
Ответ на: комментарий от i-rinat

Или вот ещё пример. В сабже написано:

float invert(float f) { 
    uint32_t raw = 0;
    memcpy(&raw, &f, sizeof(float)); 
    raw ^= (1 << 31); // инвертируем знак
    memcpy(&f, &raw, sizeof(float)); 
    return f; 
}

Что интересно: компилятор обязательно заметит, что копируемые регионы всегда заданы однозначно и с фиксированным размером, а потому сможет заменить вызов к системной функции memcpy() на регистровые операции, если оба значения будут у него «на руках» (а так, скорее всего и будет). Таким образом, никакого оверхеда на использование вызова функции здесь нет.

То есть, компилятор знает семантику memcpy() и это даже влияет на кодогенерацию. А кто-то в соседней ветке мне вчера рассказывал, что стандартная библиотека к языку не относится.

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

стандартная библиотека к языку не относится.

Как же она может не относиться, если она «стандартная»? В этом и отличие стандартной библиотеки от любой другой.

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

её стандарт - часть стандарта языка

Я в курсе, именно поэтому она называется стандартной.

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

Не знаю что это.

Что считать языком - размытый вопрос. Но вот делать выводы на основании того, что компилятор что-то там оптимизирует - это чушь. Он еще много платформоспецифичных оптимизаций делает, что, платформа - тоже часть языка?

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

gcc вообще много магии делает, вплоть до замены printf на puts. Это ничего не говорит о языке.

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

Глупый анонимус, вопрос же не про то, какие оптимизации делает компилятор, а про то, какие оптимизации ему разрешено делать, а какие - нет.

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

Переход на личности? Понемаю.

Компилятору всё разрешено, что не меняет наблюдаемого поведения. Пусть хоть Qt-шные функции оптимизирует.

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

Это был просто намек. Compilation unit - это никакая не платформа, а язык. Чтобы уметь использовать функцию тебе нужен её прототип. А чтобы сделать вышеупомянутую оптимизацию, тебе нужно знать даже не её реализацию (которая может быть неправильной - содержать ошибки), а её смысл. То есть без знания о том, что эта функция должна делать по спецификации, ты такую оптимизацию делать не имеешь права.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Забей, я неправильно распарсил дискуссию про размер байта.

Тут ещё интересную вещь вычитал на википедии: POSIX requires char to be exactly 8 bits in size. Но я повременю делать из этого какие-либо выводы.

true_admin ★★★★★
()
Ответ на: комментарий от i-rinat

Офигеть! Реально заменяет!

так, я сейчас не въехал, это шутка была или серьезно?
Для меня этот вопрос очень важен...

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

это шутка была или серьезно?

Серьёзно. Просто для меня было неожиданно.

$ cat q.c
#include <stdio.h>
int main(void) {
  printf("hello\n");
  return 0;
}

$ gcc -c q.c
$ objdump -Sr q.o

q.o:     формат файла elf64-x86-64


Дизассемблирование раздела .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	bf 00 00 00 00       	mov    $0x0,%edi
			5: R_X86_64_32	.rodata
   9:	e8 00 00 00 00       	callq  e <main+0xe>
			a: R_X86_64_PC32	puts-0x4
   e:	b8 00 00 00 00       	mov    $0x0,%eax
  13:	5d                   	pop    %rbp
  14:	c3                   	retq   
$ 

Ну и если убрать \n, то по смыслу заменить не удастся, что и видно:

$ cat q.c 
#include <stdio.h>
int main(void) {
  printf("hello");
  return 0;
}

$ gcc -g q.c
$ objdump -Sr q.o

q.o:     формат файла elf64-x86-64


Дизассемблирование раздела .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	bf 00 00 00 00       	mov    $0x0,%edi
			5: R_X86_64_32	.rodata
   9:	b8 00 00 00 00       	mov    $0x0,%eax
   e:	e8 00 00 00 00       	callq  13 <main+0x13>
			f: R_X86_64_PC32	printf-0x4
  13:	b8 00 00 00 00       	mov    $0x0,%eax
  18:	5d                   	pop    %rbp
  19:	c3                   	retq   
$ 
i-rinat ★★★★★
()
Ответ на: комментарий от reprimand

И... что же теперь?..

А что, всё правильно делает. Если есть \n в конце, printf делает то же самое, что и puts, только медленнее.

Интересно, clang так же делает?

clang 3.5 с O0 не заменяет, с O1 и O2 уже заменяет.

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

Говорят на неких DSP char - 16 бит, но живьём не видел.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от i-rinat

Офигеть! Реально заменяет!

Это хорошо, конечно, но вот некоторые функции, наоборот, неожиданно медленно работают. Например, getnameinfo() с указанием NI_NUMERICHOST и с указанием конкретного family работает в glibc ужасно медленно из-за внутренних printf()'ов. Ещё localtime_r() очень тормозная.

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

И... что же теперь?

Я ещё на gcc 4.7 с этим сталкивался, скорее всего, сделано это уже давно, брат жив. Оптимизация, вроде, логичная, никто не жалуется.

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

Экхм. Ты уверен, что спрашиваешь того человека?

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

На TMS320 серии C54/C55 sizeof(char) == sizeof(int), а размер байта 16 бит. Вот у меня на столе лежит платка, а в ящике еще одна и десяток чипов.

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

На TMS320 серии C54/C55 sizeof(char) == sizeof(int), а размер байта 16 бит.

И чем это вызвано?

На DSP всё через жопу.

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

И чем это вызвано?

Просто там 8 бит не нужно. Процессор и все его блоки заточены на математические вычисления над 16/32-разрядными числами. По этому там все выровнено по границе 16 бит (т.е. нельзя даже обратиться к произвольному байту в классическом понимании). А еще там 48-битный аккумулятор (два).

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