У меня есть вопрос о строгом псевдониме и оптимизации clang для одного примера.
Давайте рассмотрим следующий пример (1):
typedef void (*FTy)(void);
FTy F = 0;
(*F)();
Это неопределенное поведение.
Давайте рассмотрим пример (2) ниже:
typedef void (*FTy)(void);
static const FTy F = 0;
void g( int flag)
{
if ( flag )
{
(*F)();
}
}
int main( void)
{
g( 0);
return (0);
}
Косвенный вызов F по-прежнему «неопределенное поведение», но всегда находится в ложном состоянии. Так что программа должна быть правильной.
Теперь давайте рассмотрим основной пример (3):
(второе издание: благодаря упрощенной версии @Antti Haapala)
(третье издание: использование always_inline)
#include <stdio.h>
#ifndef BUGGY
#define BUGGY 1
#endif
static inline void __attribute__((always_inline)) longLongAssign( int cond, char *ptr)
{
if ( cond )
{
*((long long *)ptr) = 0;
}
}
void funcA(int s, int g)
{
int i, j = 0, k;
int grp[4] = {-1, -1};
void *ptr[2] = {(void *)&(grp[0]), 0};
for (i = 0, k = 0; i < 1; ++i) {
for (j = 0; j < 1; ++j) {
if ( grp[g] > 0 )
{
if ( g > 5 )
{
continue;
} else
{
longLongAssign( g > 3, (char *)ptr[0]);
}
}
grp[k++] = 0;
}
printf("this should be zero: %d\n", grp[0]);
}
}
int main(void) {
funcA(0, 1);
}
Скомпилируйте с помощью gcc и выполните
this should be zero: 0
Скомпилировать с помощью "clang-7.0 -O0" и выполнить
this should be zero: 0
Скомпилируйте с помощью "clang-7.0 -O1 -fno-strict-aliasing" и выполните
this should be zero: 0
Скомпилировать с помощью "clang-7.0 -O1" и выполнить
this should be zero: -1
В основном примере один из магазинов grp формально нарушает строгие псевдонимы
*((long long *)ptr) = 0;
Но этот магазин всегда находится в ложном состоянии.
Вопрос здесь такой: как работает магазин
- нарушение нарушающего правила строгого алиасинга
- но находится в недоступном утверждении
может повлиять на любой способ выполнения программы?
Правильно ли это по языку C?
Является ли приведенный ниже пример (4) правильным, хорошо определенным и не имеет неопределенного поведения?
void assign( int type, char *ptr)
{
if ( ptr )
{
if ( (type == 0) )
{
*((int *)ptr) = 1;
} else if ( (type == 1) )
{
*((float *)ptr) = 1;
} else
{
// unknown type
}
}
}
int main( void)
{
int a;
float b;
assign( 0, (char *)&a);
assign( 1, (char *)&b);
assign( 0, (char *)0);
return (0);
}
Встроенная и постоянная оптимизация распространения в функции main дает
...
if ( &a )
{
if ( (0 == 0) )
{
*((int *)&a) = 1;
} else if ( (0 == 1) )
{
*((float *)&a) = 1;
} else
{
// unknown type
}
}
...
Операция в одной руке магазина
*((float *)&a) = 1;
формально нарушает псевдонимы, но стоит в недоступном месте.
По каким причинам пример (4) может быть неверным?
Если пример (4) правильный, то почему пример (3) дает компиляцией clang разные результаты?