Re[2]: Умный вопрос по C/C++
От: Erop Россия  
Дата: 23.08.07 11:23
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А ещё одна версия — правда, дикая — то, что на целевой платформе 32-битный байт!

К>Ты уверен, что не для БЭСМ-6 компилируешь?

три вопрпоса
1) Где качнуть gcc для БЭСМ-6
2) АФАИК там байт был 48-битный
3) Как целевая платформа зависит от опции -o ?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Умный вопрос по C/C++
От: Аноним  
Дата: 23.08.07 11:28
Оценка:
Здравствуйте, Awaken, Вы писали:

А>>А можно увидеть ассемблерный листинг этого чуда? Хочется понять почему для 2-х байтового значения потребовалось более другое выравнивание, чем для 4-х байтового.


A>я делал ассемблерные листинги обоих вариантов, скомпиленных GCC 4.1.x (linux)

A>интересно то что команды в дебажном и релизном варианте не отличаются вообще.
A>но в релизном некоторые переставлены местами (для выравнивания команд на границу слова?)

А у вас получился "нерабочий" вариант? Т.е. тот который выводит неизмененное значение переменной?
Скорее всего должно получиться, как написал Егор в http://rsdn.ru/forum/message/2631549.1.aspx
Автор: Erop
Дата: 23.08.07
, т.е. значение переменной меняется, но выводится на экран значение константы, а не переменной. Адреса в таком случае должны быть одинаковыми или это уже похоже на баг оптимизатора.
Re[2]: Умный вопрос по C/C++
От: elcste  
Дата: 23.08.07 11:29
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Так вот, не могли бы знатоки популярно объяснить, когда точно возникает этот strict aliasing violation?


Не знаю, что такое strict aliasing violation, а неопределенное поведение возникает здесь:

MS>    uint16_t  hi = sp[0];

(Строго говоря, приведенный Вами код ill-formed и не является переносимым, но, как я понимаю, Вас интересовало не это.)

MS>По идее, всегда при попытке преобразования указателя к другому типу.


Нет, приведение указателей тут ни при чем.

MS>Но malloc возващает void*, который по идее надо преобразовать к нужному типу. Что, это становится нелегальным?


Нет, конечно. Указатель, возвращаемый malloc, специально выровнен так, чтобы позволить размещение в этой памяти любого объекта.

MS>Далее, например я делаю свой аллокатор, который, скажем, банально работает в статической памяти.

MS>static char mem_pool[max_size];
MS>. . .
MS>int* allocate_int()
MS>{
MS>   . . .
MS>   return (int*)(&mem_pool[index_aligned_to_int]);  // To UB or not to UB? 
MS>}

MS>Имеет ли место strict aliasing violation в этом случае?

Здесь только одна проблема: неверное выравнивание. Никаких гарантий о выравнивании статического массива символов нет.
Re[8]: Умный вопрос по C/C++
От: Alexander Pazdnikov  
Дата: 23.08.07 11:33
Оценка:
Здравствуйте, Erop, Вы писали:

AP>>Т.е. получается, что sp будет указывать по непонятному адресу? Т.е. реально вообще получить Segmentation Fault (при sp[0] = hi)?!!!

AP>>Правильно ли я понял?

E>Нет. Не правильно.

E>sp будет указывать куда-то на стек. Но вот значение переменной v2 (кажется так её там звали?) может оказаться не на стеке, а в регистре, например, в этот момент.

E>Я думаю, что в приведённом коде происходит следующее. Функция подставляется, зависимость значения переменной v2 от манипуляций с sp компилятором не отслеживается благодаря обсуждаемому правилу, соответсвенно компилятор видит, что v2 инициализируется, потом от него берут адрес, не являющийся алиасом, потом печатают, и скорее всего просто печатает константу...


И все же получается, что sp может указывать куда угодно, ну и что хорошего что стек порушиться?
Возможно в приведенном варианте так и получиться, а в более сложном случае где-нибудь в середине функции?
Хотя что тут можно обсуждать, успешно упадет или успешно неправильно обработает!!!
Re[6]: Умный вопрос по C/C++
От: ncode  
Дата: 23.08.07 14:17
Оценка: 1 (1) +1
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP>Здравствуйте, eao197, Вы писали:


E>>Выравнивание -- это не новая проблема. Но как раз в приведенном McSeem2 механизме свопинга проблем быть не должно. Поскольку uint32_t* будет выравнен на кратную 4-м границу, uint16_t* на кратную 2-м границу, а char* на любой адрес. Такие заморочки были на SPARC-ах когда-то очень давно. И ничего, все работало.


AP>Мда... Сейчас перевожу проект под ARM с Си на С++, так что чувствую, если включить -O2, то в кусках могут появиться интересные глюки, невоспроизводимые при -g ;-)


Были такие моменты у меня, когда с PC на ARM портировал проект, помню я там reinterpret_cast`ы на memcpy() менял, чтобы все работало.
Re[6]: Умный вопрос по C/C++
От: c-smile Канада http://terrainformatica.com
Дата: 23.08.07 22:48
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, Cyberax, Вы писали:


C>>Можешь явно сказать компилятору, что ты знаешь что делаешь: (int*)(void*)(&someChar[..])


MS>Кстати, хрен-на-ны.


Присоединяюсь. Воообще этот aliasing маразм какой-то. А тем более в исполнении GCC

Я вот еще поймал штучку в GCC:

struct header;

header* ptr;

assert((uint64)ptr == (uint64)(uint32)ptr);


assert срабатывает на 32bit откомпилированном коде.

(uint64)ptr в результате имеет значение 0xFFFFFFFF012345678 где 0x012345678 это реальный адрес.

Повбывав бы.
Re[6]: Умный вопрос по C/C++
От: Cyberax Марс  
Дата: 23.08.07 22:53
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>По-моему, это уже клиническая паранойя. И старческий маразм комитета.

Не волнуйся, сейчас напишем багу в GCC, чтобы здесь тоже выдавалось предупреждение
Sapienti sat!
Re[4]: Умный вопрос по C/C++
От: Awaken Украина  
Дата: 23.08.07 23:05
Оценка:
А>А у вас получился "нерабочий" вариант? Т.е. тот который выводит неизмененное значение переменной


получилось в точности как у автора поста


А>Скорее всего должно получиться, как написал Егор в http://rsdn.ru/forum/message/2631549.1.aspx
Автор: Erop
Дата: 23.08.07
, т.е. значение переменной меняется, но выводится на экран значение константы, а не переменной. Адреса в таком случае должны быть одинаковыми или это уже похоже на баг оптимизатора.


дебаг версия:
.globl swap_words
    .type    swap_words, @function
swap_words:
    pushl    %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    movzwl    2(%eax), %ecx
    movzwl    (%eax), %edx
    movw    %dx, 2(%eax)
    movw    %cx, (%eax)
    popl    %ebp
    ret
    .size


релиз:


    .p2align 4,,15
.globl swap_words
    .type    swap_words, @function
swap_words:
    pushl    %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    movzwl    2(%eax), %ecx
    movzwl    (%eax), %edx
    movw    %cx, (%eax)
    movw    %dx, 2(%eax)
    popl    %ebp
    ret


я не знаю что за директива .p2align, видимо какое-то выравнивание
Re[5]: Умный вопрос по C/C++
От: Awaken Украина  
Дата: 23.08.07 23:13
Оценка: +1
пожалуй стоит привести асмовый код полностью
там с /O3 эта функция не вызывается — она инлайнится (тогда зачем компилятор оставил ее код?)

/O1
    .file    "a.c"
    .text
.globl swap_words
    .type    swap_words, @function
swap_words:
    pushl    %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    movzwl    2(%eax), %ecx
    movzwl    (%eax), %edx
    movw    %dx, 2(%eax)
    movw    %cx, (%eax)
    popl    %ebp
    ret
    .size    swap_words, .-swap_words
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string    "%08X %08X\n"
    .text
.globl main
    .type    main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl    -4(%ecx)
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ecx
    subl    $36, %esp
    movl    $-65536, -8(%ebp)
    leal    -8(%ebp), %eax
    movl    %eax, (%esp)
    call    swap_words
    movl    -8(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    $-65536, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    movl    $0, %eax
    addl    $36, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size    main, .-main
    .ident    "GCC: (GNU) 4.1.2 20061115 (prerelease) (SUSE Linux)"
    .section    .note.GNU-stack,"",@progbits


/O3
    .file    "a.c"
    .text
    .p2align 4,,15
.globl swap_words
    .type    swap_words, @function
swap_words:
    pushl    %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    movzwl    2(%eax), %ecx
    movzwl    (%eax), %edx
    movw    %cx, (%eax)
    movw    %dx, 2(%eax)
    popl    %ebp
    ret
    .size    swap_words, .-swap_words
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string    "%08X %08X\n"
    .text
    .p2align 4,,15
.globl main
    .type    main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl    -4(%ecx)
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ecx
    subl    $36, %esp
    movzwl    -6(%ebp), %edx
    movzwl    -8(%ebp), %eax
    movl    $-65536, -8(%ebp)
    movw    %dx, -8(%ebp)
    movw    %ax, -6(%ebp)
    movl    $-65536, 8(%esp)
    movl    $-65536, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    addl    $36, %esp
    xorl    %eax, %eax
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size    main, .-main
    .ident    "GCC: (GNU) 4.1.2 20061115 (prerelease) (SUSE Linux)"
    .section    .note.GNU-stack,"",@progbits
Re[3]: Умный вопрос по C/C++
От: Шахтер Интернет  
Дата: 24.08.07 02:18
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Андрей Коростелев, Вы писали:


MS>>>
MS>>>void swap_words(uint32_t* arg)
MS>>>{
MS>>>   uint16_t* sp = (uint16_t*)arg;// Тут UB 
MS>>>   [...]
MS>>>

АК>>Правило введенное в С99 и запрещающее создание алиаса объекта с типом отличного от типа объекта-оригинала (ISO/IEC 9899 6.5/7) поддерживается в gcc 3.4.1 и выше на уровнях оптимизации начиная со 2-го. В данном случе sp не будет являться корректным алиасом для объекта *arg, потому компилятор вправе сгенерировать код, при котором sp не указывает на &(*arg).

E>Насколько я понимаю, в C++ стандарте такого ограничения нет. Тем не менее, GCC 3.4.4 для C++ генерирует такой же проблемный код, как и для C


E>McSeem2 прав -- такая паранойя. Если уж C/C++ позиционируются как языки для работы непосредственно с железом, то запрещение простого свопинга байт/слов выглядит полным маразмом.


Здесь нет запрещения "простого свопинга байт/слов".
Запрет на подобный аллиазинг -- вещь совершенно правильная, особенно для низкоуровнего программирования, поскольку помогает оптимизации кода.
Ну и как человек, который имеет некий опыт возни с разным железом -- не встречал я ещё ни разу реальной необходимости применять грязные хаки.
Обычно это делают от недостака опыта. А иногда всречается просто патологическая глупость помноженная на самоуверенность, когда человек начинает memcpy на C писать, думая, что у него получится лучше чем а CRTL.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: Умный вопрос по C/C++
От: Шахтер Интернет  
Дата: 24.08.07 02:30
Оценка: 4 (2)
Ну и в догонку.

/* main.cpp */ 

#include <stdio.h>

// assume unsigned is 32 bit

unsigned SwapHalf(unsigned val)
 {
  return (val<<16)|(val>>16);
 }
 
void SwapHalf(unsigned *var)
 {
  *var=SwapHalf(*var);
 }
 
/* main() */   

int main()
 {
  unsigned val=0xABBABEDA;
  
  SwapHalf(&val);
  
  printf("%.8X\n",val);
 
  return 0;
 }


?SwapHalf@@YAXPAI@Z PROC                ; SwapHalf, COMDAT

; 14   :   *var=SwapHalf(*var);

    mov    eax, DWORD PTR _var$[esp-4]
    mov    ecx, DWORD PTR [eax]
    rol    ecx, 16                    ; 00000010H
    mov    DWORD PTR [eax], ecx

; 15   :  }

    ret    0
?SwapHalf@@YAXPAI@Z ENDP                ; SwapHalf
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Умный вопрос по C/C++
От: Шахтер Интернет  
Дата: 24.08.07 02:53
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Smal, Вы писали:


S>>А еще лучше так (и короче, и переносимо).

B>Первый вариант тоже вполне переносим. И его тоже можно записать достаточно коротко:

B>
B>void swap_words(uint32_t* arg)
B>{
B>    union { uint32_t v; uint16_t sp[2]; } u = {*arg};
B>    std::swap(u.sp[0], u.sp[1]);
B>    *arg = u.v;
B>}
B>


Это тоже нелегально. Вот, кстати, цитата из мануаля по GCC.

Pay special attention to code like this:

union a_union {
int i;
double d;
};

int f() {
a_union t;
t.d = 3.0;
return t.i;
}

The practice of reading from a different union member than the one
most recently written to (called “type-punning”) is common. Even with
‘-fstrict-aliasing’, type-punning is allowed, provided the memory is
accessed through the union type. So, the code above will work as expected.
However, this code might not:

int f() {
a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}

В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Умный вопрос по C/C++
От: remark Россия http://www.1024cores.net/
Дата: 24.08.07 05:15
Оценка: :)
Здравствуйте, Кодт, Вы писали:

К>Ты уверен, что не для БЭСМ-6 компилируешь?


А вдруг действительно случайно так получилось?



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Умный вопрос по C/C++
От: remark Россия http://www.1024cores.net/
Дата: 24.08.07 05:36
Оценка:
Здравствуйте, eao197, Вы писали:

E>Насколько я понимаю, в C++ стандарте такого ограничения нет


Всё тоже самое с точностью до запятых (точнее замены type на dynamic type, и добавления пункта про base class type):

If a program attempts to access the stored value of an object through an lvalue of other than one of the following
types the behavior is undefined (48):
— the dynamic type of the object,
— a cv-qualified version of the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of
the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including,
recursively, a member of a subaggregate or contained union),
— a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
— a char or unsigned char type.
__________________
(48) The intent of this list is to specify those circumstances in which an object may or may not be aliased




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: aliasing и aligning
От: remark Россия http://www.1024cores.net/
Дата: 24.08.07 05:42
Оценка: 1 (1) +2
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP>Вообще, такая проблема наблюдается на процессорах, адресация в которых к данным должна быть выравнена по границе 2, 4 и т.д. (8 не встречал)


Не путайте aliasing и aligning!
Это обе засады в С++. Но тем не менее — очень разные вещи

aligning - выравнивание данных. Например, 4-ёх байтное слово должно располагаться по адресу кратному 4 байтам. Корни растут из железа.

aliasing - совмещение имен. Т.е. когда 2 указателя указывают на один и тот же объект, говорится, что это есть alias'ы объекта. Корни растут исключительно из компилятора и связано это с проведением возможных оптимизаций в коде.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Умный вопрос по C/C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 24.08.07 05:48
Оценка:
Здравствуйте, Шахтер, Вы писали:

E>>McSeem2 прав -- такая паранойя. Если уж C/C++ позиционируются как языки для работы непосредственно с железом, то запрещение простого свопинга байт/слов выглядит полным маразмом.


Ш>Здесь нет запрещения "простого свопинга байт/слов".

Ш>Запрет на подобный аллиазинг -- вещь совершенно правильная, особенно для низкоуровнего программирования, поскольку помогает оптимизации кода.
Ш>Ну и как человек, который имеет некий опыт возни с разным железом -- не встречал я ещё ни разу реальной необходимости применять грязные хаки.
Ш>Обычно это делают от недостака опыта. А иногда всречается просто патологическая глупость помноженная на самоуверенность, когда человек начинает memcpy на C писать, думая, что у него получится лучше чем а CRTL.

Ну если оставить в стороне излишнюю самоуверенность, то такие вещи, как:
* буфера ввода-вывода, указатели на которые передаются либо как void*, либо как char*;
* средства отладочных дампов блоков памяти, которые воспринимают void*, а затем преобразовывают его к char*.

они так же нелегальны?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Умный вопрос по C/C++
От: remark Россия http://www.1024cores.net/
Дата: 24.08.07 05:50
Оценка:
Здравствуйте, Андрей Коростелев, Вы писали:

АК>Правило введенное в С99 и запрещающее создание алиаса объекта с типом отличного от типа объекта-оригинала (ISO/IEC 9899 6.5/7) поддерживается в gcc 3.4.1 и выше на уровнях оптимизации начиная со 2-го. В данном случе sp не будет являться корректным алиасом для объекта *arg, потому компилятор вправе сгенерировать код, при котором sp не указывает на &(*arg).


Ты хотел сказать, что компилятор вправе думать, что sp не является алиасом для объекта *arg. И соотв. нагенерить кривого кода. Я правильно тебя понял?

А если sp не указывает на &(*arg), то куда ж ему ещё указывать?!
Во-первых, ему явно присвоили именно этот адрес.
Во-вторых, если указывать куда-то ещё, то надо создать дополнительный объект.
Тут фактически UB идёт только при доступе к объекту через sp, а при создании и инициализации sp UB нет. Т.к. далее я могу привести reinterpret_cast'ом sp обратно к uint32_t и получать доступ только через uint32_t.
[абстрагируемся на время от факта, что программа с UB имеет полностью недетерминированное поведение ]


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Умный вопрос по C/C++
От: Bell Россия  
Дата: 24.08.07 06:16
Оценка:
Здравствуйте, Шахтер, Вы писали:

Поправь меня, но ИМХО приведенный вариант с объединением в точности соответствует приведенному тобой первому варианту, который "will work as expected".
Любите книгу — источник знаний (с) М.Горький
Re[5]: Умный вопрос по C/C++
От: Erop Россия  
Дата: 24.08.07 06:28
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>
Ш>    rol    ecx, 16                    ; 00000010H
Ш>


А это точно быстрее обмена слов?
Конечно есть штраф за переход между 16 битами и 32, но если обмен можно произвести задолго до использования, скажем при чтении данных в структуру их потока с неправильным endian.

Хотя, если честно, на практике встречал только задачу перехода между big endian и little endian, а вот так, чтобы полуслова менять -- не встречал
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Умный вопрос по C/C++
От: Erop Россия  
Дата: 24.08.07 06:35
Оценка:
Здравствуйте, remark, Вы писали:

R>А если sp не указывает на &(*arg), то куда ж ему ещё указывать?!

Да он скорее всего туда и указывает.
Просто остальные пользователи *arg могут не заметить твоих последующих усилий и прочитать всё раньше, чем ты запишешь, например

R>Тут фактически UB идёт только при доступе к объекту через sp, а при создании и инициализации sp UB нет. Т.к. далее я могу привести reinterpret_cast'ом sp обратно к uint32_t и получать доступ только через uint32_t.

R>[абстрагируемся на время от факта, что программа с UB имеет полностью недетерминированное поведение ]

1) Насколько я понимаю, то если ты приведёшь туда-сюда, то вообще не будет ничего плохого. Не понятен только смысл этой деятельности
2) UB вовсе не обозначает полностью недетерминированного поведения. Это всего лишь значит, что реализация может делать что угодно. Часто конкретная реализация имеет вполне известное и детерминированное и даже документированное поведение в случае каких-то UB
3) В частности, когда ты через хаки лазаешь в "кишки" большого типа, представляя его как коллекцию маленьких, стандарт ничего не гарантирует на тему последствий. Гарантировать может в такой ситуации реализация, железо, например.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.