myprintf( "%-02d|%-2d|\n", 1, -3 );
myprintf( "%5d|\n", -12 );
myprintf( "%05d|\n", -12 );
myprintf( "%-5d|\n", -12 );
myprintf( "%-05d|\n", -12 );
for( i = -6; i < 6; i++ )
myprintf( "width=%2d|%0*d|%0*d|%*d|%*d|\n", i,
i, 123, i, -123, i, 123, i, -123);
myprintf( "%s at location %a\n", s, s );
myprintf( "%ld\n", t );
n = 1; t = 1L;
for( i=0; i < 34; i++ ){
myprintf( "for %2d |%016b|%d|%u|\n\t |%032lb|%ld|%lu|\n",
i, n, n, n, t, t, t );
n *= 2;
t *= 2;
}
myprintf( "%8x %8X\n", 7777, 7777 );
myprintf( "|%s|\n", p );
myprintf( "|%10s|\n", p );
myprintf( "|%-10s|\n", p );
myprintf( "|%20s|\n", p );
myprintf( "|%-20s|\n", p );
myprintf( "|%20.10s|\n", p );
myprintf( "|%-20.10s|\n", p );
myprintf( "|%.10s|\n", p );
}
А. Богатырев, 1992-95 - 119 - Си в UNIX
Выдача этой программы:
%abcY
abs
abs|
abs |
xyzXYZ|
xyzXYZ|
xyzXY|
xyzXY|
CDXLIV
CMXCIX
XVI
XVIII
CDLXXIX
1234
-1234
97487483
1|-3|
1 |-3|
01|-3|
1 |-3|
-12|
-0012|
-12 |
-12 |
width=-6|123 |-123 |123 |-123 |
width=-5|123 |-123 |123 |-123 |
width=-4|123 |-123|123 |-123|
width=-3|123|-123|123|-123|
width=-2|123|-123|123|-123|
width=-1|123|-123|123|-123|
width= 0|123|-123|123|-123|
width= 1|123|-123|123|-123|
width= 2|123|-123|123|-123|
width= 3|123|-123|123|-123|
width= 4|0123|-123| 123|-123|
width= 5|00123|-0123| 123| -123|
Hello, world!
at location 400980
7654321
for 0 |0000000000000001|1|1|
|00000000000000000000000000000001|1|1|
for 1 |0000000000000010|2|2|
|00000000000000000000000000000010|2|2|
for 2 |0000000000000100|4|4|
|00000000000000000000000000000100|4|4|
for 3 |0000000000001000|8|8|
|00000000000000000000000000001000|8|8|
for 4 |0000000000010000|16|16|
|00000000000000000000000000010000|16|16|
for 5 |0000000000100000|32|32|
|00000000000000000000000000100000|32|32|
for 6 |0000000001000000|64|64|
|00000000000000000000000001000000|64|64|
for 7 |0000000010000000|128|128|
|00000000000000000000000010000000|128|128|
for 8 |0000000100000000|256|256|
|00000000000000000000000100000000|256|256|
for 9 |0000001000000000|512|512|
|00000000000000000000001000000000|512|512|
for 10 |0000010000000000|1024|1024|
А. Богатырев, 1992-95 - 120 - Си в UNIX
|00000000000000000000010000000000|1024|1024|
for 11 |0000100000000000|2048|2048|
|00000000000000000000100000000000|2048|2048|
for 12 |0001000000000000|4096|4096|
|00000000000000000001000000000000|4096|4096|
for 13 |0010000000000000|8192|8192|
|00000000000000000010000000000000|8192|8192|
for 14 |0100000000000000|16384|16384|
|00000000000000000100000000000000|16384|16384|
for 15 |1000000000000000|32768|32768|
|00000000000000001000000000000000|32768|32768|
for 16 |10000000000000000|65536|65536|
|00000000000000010000000000000000|65536|65536|
for 17 |100000000000000000|131072|131072|
|00000000000000100000000000000000|131072|131072|
for 18 |1000000000000000000|262144|262144|
|00000000000001000000000000000000|262144|262144|
for 19 |10000000000000000000|524288|524288|
|00000000000010000000000000000000|524288|524288|
for 20 |100000000000000000000|1048576|1048576|
|00000000000100000000000000000000|1048576|1048576|
for 21 |1000000000000000000000|2097152|2097152|
|00000000001000000000000000000000|2097152|2097152|
for 22 |10000000000000000000000|4194304|4194304|
|00000000010000000000000000000000|4194304|4194304|
for 23 |100000000000000000000000|8388608|8388608|
|00000000100000000000000000000000|8388608|8388608|
for 24 |1000000000000000000000000|16777216|16777216|
|00000001000000000000000000000000|16777216|16777216|
for 25 |10000000000000000000000000|33554432|33554432|
|00000010000000000000000000000000|33554432|33554432|
for 26 |100000000000000000000000000|67108864|67108864|
|00000100000000000000000000000000|67108864|67108864|
for 27 |1000000000000000000000000000|134217728|134217728|
|00001000000000000000000000000000|134217728|134217728|
for 28 |10000000000000000000000000000|268435456|268435456|
|00010000000000000000000000000000|268435456|268435456|
for 29 |100000000000000000000000000000|536870912|536870912|
|00100000000000000000000000000000|536870912|536870912|
for 30 |1000000000000000000000000000000|1073741824|1073741824|
|01000000000000000000000000000000|1073741824|1073741824|
for 31 |10000000000000000000000000000000|-2147483648|2147483648|
|10000000000000000000000000000000|-2147483648|2147483648|
for 32 |0000000000000000|0|0|
|00000000000000000000000000000000|0|0|
for 33 |0000000000000000|0|0|
|00000000000000000000000000000000|0|0|
1e61 1E61
|Hello, world|
|Hello, world|
|Hello, world|
| Hello, world|
|Hello, world |
| Hello, wor|
|Hello, wor |
|Hello, wor|
2.62. Рассмотрим программу суммирования векторов:
А. Богатырев, 1992-95 - 121 - Си в UNIX
int A[1024], B[1024], C[1024];
...
for(i=0; i < 1024; i++) C[i] = A[i] + B[i];
А почему бы не
for(i=1024-1; i >=0 ; --i) ...;
А почему бы не в произвольном порядке?
foreach i in (0..1023) ...;
Данный пример показывает, что некоторые операции обладают врожденным паралеллизмом,
ведь все 1024 сложений можно было бы выполнять параллельно! Однако тупой компилятор
будет складывать их именно в том порядке, в котором вы ему велели. Только самые сов-
ременные компиляторы на многопроцессорных системах умеют автоматически распараллели-
вать такие циклы. Сам язык Си не содержит средств указания параллельности (разве что
снова - библиотеки и системные вызовы для этого).
А. Богатырев, 1992-95 - 122 - Си в UNIX
3. Мобильность и машинная зависимость программ. Проблемы с русскими буквами.
Программа считается мобильной, если она без каких-либо изменений ее исходного
текста (либо после настройки некоторых констант при помощи #define и #ifdef) трансли-
руется и работает на разных типах машин (с разной разрядностью, системой команд,
архитектурой, периферией) под управлением операционных систем одного семейства. Заме-
тим, что мобильными могут быть только исходные тексты программ, объектные модули для
разных процессоров, естественно, несовместимы!
3.1. Напишите программу, печатающую размер типов данных char, short, int, long,
float, double, (char *) в байтах. Используйте для этого встроенную операцию sizeof.
3.2. Составьте мобильную программу, выясняющую значения следующих величин для любой
машины, на которой работает программа:
1) Наибольшее допустимое знаковое целое.
2) Наибольшее беззнаковое целое.
3) Наибольшее по абсолютной величине отрицательное целое.
4) Точность значения |x|, отличающегося от 0, где x - вещественное число.
5) Наименьшее значение e, такое что машина различает числа 1 и 1+e (для веществен-
ных чисел).
3.3. Составьте мобильную программу, выясняющую длину машинного слова ЭВМ (число
битов в переменной типа int). Указание: для этого можно использовать битовые сдвиги.
3.4. Надо ли писать в своих программах определения
#define EOF (-1)
#define NULL ((char *) 0) /* или ((void *)0) */
Ответ: НЕТ. Во-первых, эти константы уже определены в include-файле, подключаемом по
директиве
#include
поэтому правильнее написать именно эту директиву. Во-вторых, это было бы просто неп-
равильно: конкретные значения этих констант на данной машине (в данной реализации
системы) могут быть другими! Чтобы придерживаться тех соглашений, которых придержива-
ются все стандартные функции данной реализации, вы ДОЛЖНЫ брать эти константы из
.
По той же причине следует писать
#include
int fd = open( имяФайла, O_RDONLY); /* O_WRONLY, O_RDWR */
вместо
int fd = open( имяФайла, 0); /* 1, 2 */
3.5. Почему может завершаться по защите памяти следующая программа?
#include
#include
time_t t;
extern time_t time();
...
t = time(0);
/* узнать текущее время в секундах с 1 Янв. 1970 г.*/
Ответ: дело в том, что прототип системного вызова time() это:
time_t time( time_t *t );
то есть аргумент должен быть указателем. Мы же вместо указателя написали в качестве
А. Богатырев, 1992-95 - 123 - Си в UNIX
аргумента 0 (типа int). На машине IBM PC AT 286 указатель - это 2 слова, а целое -
одно. Недостающее слово будет взято из стека произвольно. В результате time() полу-
чает в качестве аргумента не нулевой указатель, а мусор. Правильно будет написать:
t = time(NULL);
либо (по определению time())
time( &t );
а еще более корректно так:
t = time((time_t *)NULL);
Мораль: везде, где требуется нулевой указатель, следует писать NULL (или явное приве-
дение нуля к типу указателя), а не просто 0.
3.6. Найдите ошибку:
void f(x, s) long x; char *s;
{
printf( "%ld %s\n", x, s );
}
void main(){
f( 12, "hello" );
}
Эта программа работает на IBM PC 386, но не работает на IBM PC 286.
Ответ. Здесь возникает та же проблема, что и в примере про sin(12). Дело в том,
что f требует первый аргумент типа long (4 байта на IBM PC 286), мы же передаем ей
int (2 байта). В итоге в x попадает неверное значение; но более того, недостающие
байты отбираются у следующего аргумента - s. В итоге и адрес строки становится непра-
вильным, программа обращается по несуществующему адресу и падает. На IBM PC 386 и
int и long имеют длину 4 байта, поэтому там эта ошибка не проявляется!
Опять-таки, это повод для использования прототипов функций (когда вы прочитаете
про них - вернитесь к этому примеру!). Напишите прототип
void f(long x, char *s);
и ошибки не будет.
В данном примере мы использовали тип void, которого не сушествовало в ранних
версиях языка Си. Этот тип означает, что функция не возвращает значения (то есть
является "процедурой" в смысле языков Pascal или Algol). Если мы не напишем слово
void перед f, то компилятор будет считать функцию f возвращающей целое (int), хотя
эта функция ничего не возвращает (в ней нет оператора return). В большинстве случаев
это не принесет вреда и программа будет работать. Но зато если мы напишем
int x = f((long) 666, "good bye" );
то x получит непредсказуемое значение. Если же f описана как void, то написанный опе-
ратор заставит компилятор сообщить об ошибке.