Olej писал(а):Вопросы использования Clang, а главный из таких вопросов остаётся
степень совместимости по коду с GCC, будут попутно упоминаться в теме:
язык C в Linux: вопросы начального уровня. Но там, как и понятно из названия, только относительно использования Clang для языка C (не C++).
Ещё раз столкнулся с вопросами совместимости кода для GCC и Clang (относительно языка C).
Это очень важно, т.к. объявлено, что:
Целью проекта Clang является создание замены GNU Compiler Collection (GCC)
В 2013г. было объявлено, что с помощью Clang было полностью собрано ядро Linux из оригинальных исходных кодов - это очень высокая степень совместимости.
Но язык C имеет достаточно много расширений, нескольких разных родов:
- расширения стандартами C89, C99 - комплексные числа и арифметика, языковая локализация и широкие символы wchar_t и т.д.
- расширения, которые вносит только проект GCC GNU: инлайновые ассемблерные вставки, вложенные описания функций и т.д.
Интересна совместимость вот в смысле расширений.
Вот несколько таких тестов:
Код: Выделить всё
//---------------------------------------------------------
static void show( int *arr, int row, int col ) {
int r, c;
printf( "матрица : %d x %d [ %d ]\n",
row, col, row * col );
for( r = 0; r < row; r++ ) {
for( c = 0; c < col; c++ )
printf( "%3d", arr[ r * col + c ] );
printf( "\n" );
}
}
static void transpa( int *arr, int *row, int *col ) {
int r, c;
int wrk[ *row * *col ]; // массив с динамической размерностью
for( r = 0; r < *row; r++ )
for( c = 0; c < *col; c++ ) {
int i1 = r * *col + c,
i2 = c * *row + r;
wrk[ i2 ] = arr[ i1 ];
}
for( r = 0; r < *row * *col; r++ ) {
arr[ r ] = wrk[ r ];
}
r = *row;
*row = *col;
*col = r;
}
#define COL 5
#define ROW 2
void test02( void ) { // динамические массивы (C99)
int c[ ROW ][ COL ] = {
{ 1, 2, 3, 4, 5 },
{ 2, 3, 4, 5, 6 }
},
col = COL, row = ROW;
show( (int*)c, row, col );
printf( "транспонирование не квадратной матрицы:\n" );
transpa( (int*)c, &row, &col );
show( (int*)c, row, col );
}
//---------------------------------------------------------
static unsigned long long rdtsc( void ) {
unsigned long long int x;
asm volatile ( "rdtsc" : "=A" (x) ); // команда RDTSC
return x;
}
void test03( void ) { // ассемблерные вставки (GCC)
time_t t1, t2;
unsigned long long cf, cs;
time( &t1 );
while( t1 == time( &t2 ) ) cf = rdtsc(); // начало очередной секунды
while( t2 == time( &t1 ) ) cs = rdtsc(); // завершение этой секунды
printf( "тактовая частота процессора %.3f Ghz\n",
(double)( cs - cf ) / 1.E9 );
}
//---------------------------------------------------------
typedef struct vararr {
int n, data[ 0 ];
} vararr_t;
void varfunc( vararr_t *a ) {
int ni = a->n, j;
printf( "массив размера %d\t=> { ", ni );
int *va = (int*)a;
for( j = 1; j <= ni; j++ )
printf( "%d%s", va[ j ], j != ni ? " , " : " }\n" );
}
void test04( void ) {
printf( "структуры переменного размера:\n" );
int var[] = { 3, 5, 7, 10 }, i;
for( i = 0; i < sizeof( var ) / sizeof( *var ); i++ ) {
int len = var[ i ], j;
vararr_t *arr = (vararr_t*)calloc( len + 1, sizeof( int ) );
arr->n = len;
for( j = 0; j < len; j++ ) arr->data[ j ] = j + 1;
varfunc( arr );
free( arr );
}
}
//---------------------------------------------------------
#define DIV 10.
void test05( void ) { // максимальная точность итерационных вычислений
printf( "максимальная точность итерационных вычислений:\n" );
int i;
float x = 1.;
double y = 1.;
long double z = 1.;
for( i = 0; ; i++ ) {
if( (float)1. + x == (float)1. + x / (float)DIV ) break;
x /= (float)DIV;
}
printf( "для float\t: %e (число итераций %d)\n", x, i );
for( i = 0; ; i++ ) {
if( ( (double)1. + y ) == ( (double)1. + y / (double)DIV ) ) break;
y /= (double)DIV;
}
printf( "для double\t: %e (число итераций %d)\n", y, i );
for( i = 0; ; i++ ) {
if( ( (long double)1. + z ) == ( (long double)1. + z / (long double)DIV ) ) break;
z /= (long double)DIV;
}
printf( "для long double\t: %Le (число итераций %d)\n", z, i );
}
//---------------------------------------------------------
Видно, что тесты выполняются успешно:
Код: Выделить всё
olej@notebook:~/2014_WORK/OWN.BOOKS/BOOK.IBM/C/EXMP$ make -fMakefile.clang clang
clang -xc -Wall -lm -O clang.c -o clang
olej@notebook:~/2014_WORK/OWN.BOOKS/BOOK.IBM/C/EXMP$ ./clang
00 ---------------------------------------
матрица : 2 x 5 [ 10 ]
1 2 3 4 5
2 3 4 5 6
транспонирование не квадратной матрицы:
матрица : 5 x 2 [ 10 ]
1 2
2 3
3 4
4 5
5 6
01 ---------------------------------------
тактовая частота процессора 1.662 Ghz
02 ---------------------------------------
структуры переменного размера:
массив размера 3 => { 1 , 2 , 3 }
массив размера 5 => { 1 , 2 , 3 , 4 , 5 }
массив размера 7 => { 1 , 2 , 3 , 4 , 5 , 6 , 7 }
массив размера 10 => { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }
03 ---------------------------------------
максимальная точность итерационных вычислений:
для float : 9.999999e-09 (число итераций 8)
для double : 1.000000e-16 (число итераций 16)
для long double : 1.000000e-20 (число итераций 20)
------------------------------------------
Интересный последний тест - максимальная точность итерационных вычислений.
Если его же компилировать GCC получим:
Код: Выделить всё
olej@notebook:~/2014_WORK/OWN.BOOKS/BOOK.IBM/C/EXMP$ ./clang 3
03 ---------------------------------------
максимальная точность итерационных вычислений:
для float: 1.000000e-08 (число итераций 8)
для double: 1.000000e-16 (число итераций 16)
для long double: 1.000000e-20 (число итераций 20)
------------------------------------------
Обратим внимание на то, что результат Clang (9.999999e-09) совпадает с полученным в GCC (1.000000e-08)
по смыслу, но не совпадает
по численному представлению. Это должно быть напоминанием, что при переносе кода под Clang не следует ожидать
формальной численной идентичности, такое предположение может создать серьёзные трудности в отладке кода. Ещё более выраженным это будет при вовлечении оптимизации (-O2, -O3 и т.д.) генерируемого кода (уровень которой, как утверждается, у Clang потенциально значительно выше, чем у GCC).