2010-01-12 4 views
72

C99 существует уже более 10 лет, но поддержка для него идет медленно, поэтому большинство разработчиков застряли на C89. Даже сегодня я иногда слегка удивляюсь, когда сталкиваюсь с функциями C99 в коде C.Каковы наиболее полезные новые функции на C99?

Теперь, когда большинство основных компиляторов поддерживают C99 (MSVC является заметным исключением, а некоторые встроенные компиляторы также отстают), я считаю, что разработчики, которые работают с C, вероятно, должны знать, какие функции C99 доступны для них. Некоторые из функций - это обычные функции, которые раньше не были стандартизованы (например, snprintf) или знакомы с C++ (размещение объявления гибкой переменной или однострочные комментарии //), но некоторые из новых функций были впервые представлены на C99 и незнакомы многим программистам.

Что вы найдете в списке самых полезных функций C99?

Для справки, the C99 standard (обозначен как черновик, но идентичный обновленному стандарту, насколько мне известно), list of new features и GCC C99 implementation status.

Одна функция за каждый ответ, пожалуйста; не стесняйтесь оставлять несколько ответов. Приводятся примеры коротких примеров, демонстрирующих новые функции.

+2

Должна быть аналогичная wiki для функций, которые люди * ненавидят * в C99! –

+0

Ну, возник вопрос о вредных или неподдерживаемых функциях C99 http://stackoverflow.com/questions/1898890/what-c99-features-are-considered-harmful-or-unsupported –

+0

Спасибо. Вы должны изменить текст ссылки, чтобы указать, что это черновик, а не фактический стандарт, и ссылка на n1256, пока вы на нем :-). BTW, глядя на http://gcc.gnu.org/c99status.html, я бы не сказал, что большая часть C99 поддерживается gcc. А поскольку gcc является одним из наиболее широко используемых компиляторов C, ... –

ответ

8

Лично мне нравится подтверждение IEC 60559:1989 (двоичная арифметика с плавающей запятой для микропроцессорных систем) и гораздо лучшая поддержка с плавающей запятой.

В том же духе настройка и запрос режима округления с плавающей запятой, проверка номеров Nan/Infinity/subnormal и т. Д. - это здорово.

+0

Ну, MS не любит это делать. –

+0

C не очень хорошо разработан для концепции режимов округления, так как они означают, что математика с плавающей запятой должна рассматриваться как имеющая побочные эффекты. Наличие чего-то лучшего, чем «надежды на лучшую» семантику с плавающей запятой, полезно, но я не знаю, сколько реализаций действительно соблюдают все требования Приложения F. – supercat

48

Поддержка однострочных комментариев, начинающихся с //.

+6

+1 ВСЕ компиляторы, которые, как я знаю, уже поддерживают это. Пришло время упомянуть в стандарте. – slebetman

64

stdint.h, который определяет int8_t, uint8_t и т. Д. Больше не нужно делать переносные предположения о том, насколько широки ваши целые числа.

uint32_t truth = 0xDECAFBAD; 
+18

Лучшая гексагональная фраза с DE: AD: BE: EF: CA: FE. –

+0

Что означает декафбад? – Pacerier

+5

@Pacerier Это просто произвольная шестнадцатеричная константа, используемая для иллюстрации примера. Но для значения юмора он произносит «decaf bad», подразумевая, что кофе без кофеина уступает реальности. –

33

Вариадические макросы. Легче создавать шаблонный код с неограниченным количеством аргументов.

71

Я так привык печатать

for (int i = 0; i < n; ++i) { ... } 

в C++, что это боль, чтобы использовать не C99 компилятор, где я вынужден сказать

int i; 
for (i = 0; i < n; ++i) { ... } 
+40

Кроме того, он сужает область переменной int, что всегда хорошо. ^^ – helpermethod

+0

Это тоже было бы моим выбором. – figurassa

+2

@Oliver , но затем удаляются инструкции 'sub esp, 4' и' add esp, 4'!

18

Поддержка inline функций.

+0

На практике GCC обычно игнорирует ключевое слово inline при принятии решения о том, какие функции встроены и автоматически строит объекты на основе собственной эвристики, если вы не заставляете это делать иначе. – daf

+5

daf: 'inline' все еще помогает, потому что он позволяет вам определить функцию в нескольких единицах перевода, поэтому вы можете поместить ее в заголовочный файл, который дает возможности кросс-модуля. – caf

+0

@daf 'inline __attribute __ ((force_inline))' –

62

Я думаю, что новые механизмы инициализатора чрезвычайно важны.

struct { int x, y; } a[10] = { [3] = { .y = 12, .x = 1 } }; 

ОК - не является убедительным примером, но эти обозначения точны. Вы можете инициализировать определенные элементы массива и конкретные элементы структуры.

Может быть, лучший пример будет это - хотя я признаю, что это не очень убедительным:

enum { Iron = 26, Aluminium = 13, Beryllium = 4, ... }; 

const char *element_names[] = 
{ 
    [Iron]  = "Iron", 
    [Aluminium] = "Aluminium", 
    [Beryllium] = "Beryllium", 
    ... 
}; 
+5

Это убедительная демонстрация. Существует огромное количество перечислимых таблиц с соответствующими строковыми таблицами. – u0b34a0f6ae

+1

Определения могут также работать –

+4

@ColeJohnson: Если вы внимательно посмотрите на второй пример, вы увидите, что инициализаторы указаны не в порядке, но будут работать правильно. Это невозможно сделать просто с помощью определений. Первый пример инициализирует только индекс 4 массива; это невозможно сделать просто с помощью определений. –

26

Compound литералов.Настройка структуры член-на-член так '89;)

Вы также можете использовать их, чтобы получить указатели на объекты с автоматической продолжительностью хранения без объявляющего ненужных переменных, например

foo(&(int){ 4 }); 

insteand из

int tmp = 4; 
foo(&tmp); 
+12

no & 4? : (((((( –

39

Возможность объявлять переменные в местах, отличных от начала блока.

+2

) Я не очень увлекаюсь этим. На мой взгляд, переменные не только должны вноситься в область действия по мере необходимости, но и удаляться из области действия, когда это не требуется. Переменные mid-block почти всегда висят вокруг дольше, чем нужно. – supercat

+3

@supercat вы бы предпочли «int a; int b; a = f(); b = g();' to 'int a = f(); int b = g();' «объявление переменной, близкой к тому, где она инициализируется, огромно для уменьшения ошибок. –

+0

@RyanHaining: Альтернативно, создайте блок вложенной области видимости (просто хочу, чтобы был стандартный синтаксис, в котором сказано, что« этот блок предназначен только для определения области видимости », можно использовать легко использовать нулевой макрос для этой цели, но это кажется немного уродливым. – supercat

47

массивы переменной длины:

int x; 
scanf("%d", &x); 
int a[x]; 
for (int i = 0; i < x; ++i) 
    a[i] = i * i; 
for (int i = 0; i < x; ++i) 
    printf("%d\n", a[i]); 
+3

Вы действительно думаете, что массивы VLA настолько велики? C11 делает их необязательными. –

+1

Просто не забудьте применить входную санитарию, чтобы предотвратить переполнение стека (или повреждение стека , если x отрицательно): 'if (x <0) x = 0, else if (x> 1024) x = 1024;' – daddesio

23

Тип BOOL.

Теперь вы можете сделать что-то вроде этого:

bool v = 5; 

printf("v=%u\n", v); 

напечатает

1 
+1

Кто бы ни думал об этом, то это чисто гениальный –

+3

Не 'v = 1'? Магия! –

+0

Нет, 'bool' в C99 принудительно присваивает значение, назначенное переменной, всегда 1 или 0. Вот почему вы должны быть осторожны, если у вас есть код, который работает на компиляторе C99 и на более старом языке с« имитированным »' bool 'типа. Использование '!!' сделает этот перенос. 'v = !! 5;' имеет одинаковую семантику, но не читается. –

14

поддержка юникода последовательность выхода:

printf("It's all \u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC to me.\n"); 

или даже буквальные Unicode символы:

printf("日本語\n"); 

(примечание: может не работать в зависимости от вашей локали; портативная поддержка для разных кодировок займет больше работы)

30

snprintf() - серьезно, это стоит того, чтобы сделать безопасные форматированные строки.

+0

Очень верно. Я собирался добавить этот ответ сам, если никто другой не сделал. –

28

Гибкие элементы массива.

6.7.2.1 Структура и объединение также указывает, ERS

В особом случае, последний элемент структуры с более чем одним именем элемента может иметь неполный тип массива; это называется элементом гибкой решетки. За двумя исключениями элемент гибкого массива игнорируется. Во-первых, размер структуры должна быть равно смещение последнего элемента другой идентичной структуры, которая заменяет гибкую элемент массива с массивом unspeci фи длины изд) Во-вторых, когда . (или ->) оператора имеет левый операнд, который является (указателем на) структуру с элементом гибкого элемента массива, а правый операнд - этим членом, он ведет себя так, как если бы этот элемент был заменен самым длинным массивом (с тем же типом элемента), который не сделал бы структура больше, чем доступ к объекту; смещение массива должно оставаться равным элементу гибкого элемента массива, даже если это будет отличаться от размера заменяющего массива. Если этот массив не будет содержать никаких элементов, он будет вести себя так, как если бы у него был один элемент, но поведение не было определено, если была предпринята попытка получить доступ к этому элементу или сгенерировать указатель один за ним .

Пример:

typedef struct { 
    int len; 
    char buf[]; 
} buffer; 

int bufsize = 100; 
buffer *b = malloc(sizeof(buffer) + sizeof(int[bufsize])); 
+1

+1 для окончательного создания этого кошерного. Это в каждом коде сокета TCP/IP, который я когда-либо видел. – slebetman

+0

В самом деле, я считаю это гораздо более кошерным, чем обычный трюк с использованием buf [1] и вычитание 1 из размера malloc. Трюк может быть общим, но я бы рассматривал его как Undefined Behavior (надлежащим образом использовал бы buf [MAX_SIZE] и вычитал MAX_SIZE из размера malloc), поскольку код индексирования компилятора может зависеть от предполагаемого размера buf []. – supercat

10

шестнадцатеричные константы с плавающей точкой (0x1.8p0f) и спецификаторов преобразования (%a, %A). Если вы часто обращаетесь к низкоуровневым числовым данным, это огромное улучшение по сравнению с десятичными буквами и конверсиями.

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

+2

Да, я просто использовал их на днях, пытаясь объяснить кому-то, как числа с плавающей запятой работают в другом вопросе переполнения стека. –

15

Ключевое слово restrict. Особенно, когда вы хруст номера ...

16

Compound литералов, уже упоминавшийся, но вот мой убедительный пример:

struct A *a = malloc(sizeof(*a)); 
*a = (struct A){0}; /* full zero-initialization */ 
/* or */ 
*a = (struct A){.bufsiz=1024, .fd=2}; /* rest are zero-initialized. */ 

Это ясно для инициализации данных, даже если это в куче. Невозможно забыть нулевое инициализацию.

Смежные вопросы