Скрытые возможности C

Я знаю, что за всеми реализациями компилятора C стоит стандарт, поэтому не должно быть никаких скрытых возможностей. Несмотря на это, я уверен, что все разработчики C имеют скрытые / секретные приемы, которые они используют постоянно.

141
задан 6 revs, 5 users 50% 25 September 2017 в 20:52
поделиться

44 ответа

Указатели функции. Можно использовать таблицу указателей функции, чтобы реализовать, например, быстро косвенно поточные интерпретаторы кода (Forth) или диспетчеры байт-кода, или моделировать подобные OO виртуальные методы.

Тогда существуют скрытые сокровища в стандартной библиотеке, такие как qsort (), bsearch (), strpbrk (), strcspn () [последние два, являющиеся полезным для реализации strtok () замена].

ошибка А C - то, что арифметическое переполнение со знаком является неопределенным поведением (UB). Таким образом каждый раз, когда Вы видите выражение, такое как x+y, и подписываемый ints, он мог бы потенциально переполнить и вызвать UB.

62
ответ дан zvrba 25 September 2017 в 20:52
поделиться
  • 1
    Это выглядит хорошим, но необходимо показать пример, иначе, это должен быть комментарий – Juan Mendes 4 May 2013 в 19:10

регистровые переменные

я раньше объявлял, что некоторые переменные с register ключевое слово помогают вещам скорости встать. Это дало бы подсказку компилятору C для использования регистра ЦП в качестве локального устройства хранения данных. Это наиболее вероятно больше не необходимое, поскольку современные дневные компиляторы C делают это автоматически.

1
ответ дан Mark Stock 25 September 2017 в 20:52
поделиться
  • 1
    Почему это - плохое решение? Возможно, Samuel' s процесс таково, что угон сессии не является проблемой. Единственный способ действительно решить перехват сеанса (незаметным способом) использует SSL для всех связанных с сессией запросов. Если бы Samuel волновался по поводу пропускаемых данных, он должен использовать SSL. – Stephen Holiday 23 September 2010 в 18:30

структура инициализации к нулю

struct mystruct a = {0};

это обнулит все stucture элементы.

63
ответ дан mike511 25 September 2017 в 20:52
поделиться

gcc имеет много расширений языка C, которым я наслаждаюсь, который может быть найден здесь . Часть моего избранного функциональные атрибуты . Одним чрезвычайно полезным примером является атрибут формата. Это может использоваться при определении пользовательской функции, которая берет printf строку формата. При включении этого функционального атрибута gcc сделает, проверяет аргументы, чтобы гарантировать, чтобы строка формата и аргументы совпали и генерировали предупреждения или ошибки как соответствующие.

int my_printf (void *my_object, const char *my_format, ...)
            __attribute__ ((format (printf, 2, 3)));
24
ответ дан Russell Bryant 25 September 2017 в 20:52
поделиться
  • 1
    Прекрасный.. но я полагаю, что любое время, Вы выдаете исключения, бросая полезный тип исключительной ситуации, абсолютно необходимо. – markt 21 March 2009 в 18:30

Мой фаворит "скрытая" функция C, использование %n в printf для обратной записи к стеку. Обычно printf выталкивает значения параметров от стека на основе строки формата, но %n может записать их обратно.

раздел Выезда 3.4.2 здесь . Может привести к большому количеству противных уязвимостей.

8
ответ дан Sridhar Iyer 25 September 2017 в 20:52
поделиться
  • 1
    Что происходит в том коде, если firstName является пустым? Wouldn' t NullRef следуют? Никогда не пытался видеть, могут ли Дополнительные Методы все еще присоединить к нулевому указателю. – Jarrod Dixon♦ 22 March 2009 в 03:35

Ранние версии gcc попытались выполнить игру каждый раз, когда он встретился с "#pragma" в исходном коде. См. также здесь .

3
ответ дан Sec 25 September 2017 в 20:52
поделиться
  • 1
    как только мы связываем сервис от первого действия, и мы используем тот сервис, мы развяжем его. поэтому предположите в моем следующем действии, если мы хотим использовать тот же сервис, должны ли мы связать его снова там право, или неправ ли я в процессе. – bHaRaTh 28 February 2011 в 05:34

Мне показали это в небольшом количестве кода однажды и спросил, что он сделал:


hexDigit = "0123456789abcdef"[someNybble];

Другой фаворит:


unsigned char bar[100];
unsigned char *foo = bar;
unsigned char blah = 42[foo];
3
ответ дан 2 revs 25 September 2017 в 20:52
поделиться
  • 1
    можно связать с тем же сервисом от другого действия точно так же, как Вы сделали здесь. – Samuh 28 February 2011 в 06:17

Преобразование типов при помощи необычных преобразований типа. Хотя не скрытая функция, его довольно хитрое.

Пример:

, Если необходимо было знать, как плавание хранилищ компилятора, просто попробуйте это:

uint32_t Int;
float flt = 10.5; // say

Int = *(uint32_t *)&flt;

printf ("Float 10.5 is stored internally as %8X\n", Int);

или

float flt = 10.5; // say

printf ("Float 10.5 is stored internally as %8X\n", *(uint32_t *)&flt);

Примечание умное использование преобразований типа. Преобразование адреса переменной (здесь & flt) к желаемому типу (здесь (uint32_t *)) и извлечение его содержания (применение '*').

Это работает другая сторона выражения также:

*(float *)&Int = flt;

Это могло также быть выполнено с помощью объединения:

typedef union
{
  uint32_t Int;
  float    flt;

} FloatInt_type;
3
ответ дан 2 revs, 2 users 93% 25 September 2017 в 20:52
поделиться

Едва ли скрытая функция, но это смотрело на меня как вуду, в первый раз, когда я видел что-то вроде этого:


void callback(const char *msg, void *data)
{
    // do something with msg, e.g.
    printf("%s\n", msg);

    return;
    data = NULL;
}

причина этой конструкции, это при компиляции этого с-Wextra и без "данных = ПУСТОЙ УКАЗАТЕЛЬ"; - строка, gcc выложит предупреждение о неиспользованных параметрах. Но с этой бесполезной строкой Вы не получаете предупреждение.

РЕДАКТИРОВАНИЕ: Я знаю, что существуют другие (лучшие) способы предотвратить те предупреждения. Это просто выглядело странным для меня, в первый раз, когда я видел это.

2
ответ дан 2 revs 25 September 2017 в 20:52
поделиться
  • 1
    AsyncTask не будет полезен, когда у Вас будет код для выполнения, не запуская приложение. – Erol 3 July 2012 в 23:17

Мне понравились измеренные структуры переменной, которые Вы могли сделать:

typedef struct {
    unsigned int size;
    char buffer[1];
} tSizedBuffer;

tSizedBuffer *buff = (tSizedBuffer*)(malloc(sizeof(tSizedBuffer) + 99));

// can now refer to buff->buffer[0..99].

Также offsetof макрос, который находится теперь в ANSI C, но был частью колдовства в первый раз, я видел его. Это в основном использует операцию вычисления адреса (&) для нулевого указателя, переделанного как переменная структуры.

5
ответ дан paxdiablo 25 September 2017 в 20:52
поделиться
  • 1
    Как может я использовать этот код, когда я отправляю форму с целью =" myIFrame" указать на iframe?? – ShivarajRH 2 December 2013 в 08:59

Выборка :

На этой странице, Вы найдете список интересного C программированием вопросов/загадок, Эти перечисленные программы являются теми, которых я принял как электронная почта вперед от моих друзей, некоторые я читал в некоторых книгах, некоторых из Интернета и некоторых на основе моих событий кодирования в C.

http://www.gowrikumar.com/c/index.html

1
ответ дан Özgür 25 September 2017 в 20:52
поделиться
  • 1
    @zolex, что является настолько трудным о прерывании данных сообщения? Нахождение в кафе с выполнением WireShark - все, что необходимо угнать данные POST. Воссоздайте запрос с cookie и отправьте данные, и Вы хороши для движения. Если Вы полагаете, что сессии плохое решение, то SSL является единственным хорошим решением. – riwalk 24 September 2010 в 18:44
int8_t
int16_t
int32_t
uint8_t
uint16_t
uint32_t

Это дополнительный объект в стандарте, но это должна быть скрытая функция, потому что люди постоянно переопределяют их. Одна кодовая база я продолжил работать (и все еще делают, на данный момент) имеет несколько переопределений, все с различными идентификаторами. Большую часть времени это с макросами препроцессора:

#define INT16 short
#define INT32  long

И так далее. Это заставляет меня хотеть вытащить волосы. Просто используют чертовски стандартные целочисленные определения типов!

77
ответ дан Ben Collins 25 September 2017 в 20:52
поделиться

Мультисимвольные константы:

int x = 'ABCD';

Это устанавливает x на 0x41424344 (или 0x44434241, в зависимости от архитектуры).

РЕДАКТИРОВАНИЕ: Эта техника не является портативной, особенно при сериализации интервала Однако, может быть чрезвычайно полезно создать перечисления самодокументирования. например,

enum state {
    stopped = 'STOP',
    running = 'RUN!',
    waiting = 'WAIT',
};

Это делает его намного более простым, если Вы смотрите на необработанный дамп памяти и должны определить значение перечисления, не имея необходимость искать его.

52
ответ дан 5 revs, 3 users 88% 25 September 2017 в 20:52
поделиться

C99-разработайте макросы аргумента переменной, иначе

#define ERR(name, fmt, ...)   fprintf(stderr, "ERROR " #name ": " fmt "\n", \
                                  __VAR_ARGS__)

, который использовался бы как

ERR(errCantOpen, "File %s cannot be opened", filename);

Здесь, я также использую stringize оператор и строковую константу concatentation, другие функции, которые я действительно люблю.

7
ответ дан Ben Combee 25 September 2017 в 20:52
поделиться

Переменные автоматические переменные размера также полезны в некоторых случаях. Они были добавлены я nC99 и поддерживались в gcc в течение долгого времени.

void foo(uint32_t extraPadding) {
    uint8_t commBuffer[sizeof(myProtocol_t) + extraPadding];

Вы заканчиваете с буфером на стеке с комнатой для заголовка протокола фиксированного размера плюс переменные данные размера. Можно получить тот же эффект с alloca (), но этот синтаксис более компактен.

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

6
ответ дан DGentry 25 September 2017 в 20:52
поделиться

Больше приема компилятора GCC, но можно дать подсказки признака ответвления компилятору (распространенный в ядре Linux)

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

, см.: http://kerneltrap.org/node/4705

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

void foo(int arg)
{
     if (unlikely(arg == 0)) {
           do_this();
           return;
     }
     do_that();
     ...
}
116
ответ дан tonylo 25 September 2017 в 20:52
поделиться

Оператор запятой широко не используется. Этим можно, конечно, злоупотребить, но это может также быть очень полезно. Это использование является наиболее распространенным:

for (int i=0; i<10; i++, doSomethingElse())
{
  /* whatever */
}

, Но можно использовать этот оператор где угодно. Наблюдайте:

int j = (printf("Assigning variable j\n"), getValueFromSomewhere());

Каждый оператор оценен, но значение выражения будет значением последнего оцененного оператора.

73
ответ дан Ben Collins 25 September 2017 в 20:52
поделиться

Я никогда не использовал битовые поля , но они звучат прохладными для материала ультранизкого уровня.

struct cat {
    unsigned int legs:3;  // 3 bits for legs (0-4 fit in 3 bits)
    unsigned int lives:4; // 4 bits for lives (0-9 fit in 4 bits)
    // ...
};

cat make_cat()
{
    cat kitty;
    kitty.legs = 4;
    kitty.lives = 9;
    return kitty;
}

Это означает, что sizeof(cat) может быть столь же маленьким как sizeof(char).

<час>

Объединенные комментарии Aaron и leppie, парни спасибо.

44
ответ дан 4 revs 25 September 2017 в 20:52
поделиться

Чередование структур как Устройство Вареного пудинга :

strncpy(to, from, count)
char *to, *from;
int count;
{
    int n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}
37
ответ дан 6 revs, 4 users 88% 25 September 2017 в 20:52
поделиться
  • 1
    What' s Ваша определенная проблема? Можно ли отправить некоторый код? – Mike Sickler 11 June 2010 в 04:50

C имеет стандарт, но не все компиляторы C полностью совместимы (я еще не видел полностью совместимого компилятора C99!).

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

, Например: свопинг двух целых чисел без знака, не используя временную переменную:

...
a ^= b ; b ^= a; a ^=b;
...

или "расширяющийся C" для представления конечные автоматы как:

FSM {
  STATE(x) {
    ...
    NEXTSTATE(y);
  }

  STATE(y) {
    ...
    if (x == 0) 
      NEXTSTATE(y);
    else 
      NEXTSTATE(x);
  }
}

, который может быть достигнут со следующими макросами:

#define FSM
#define STATE(x)      s_##x :
#define NEXTSTATE(x)  goto s_##x

В целом, тем не менее, мне не нравятся приемы, которые умны, но делают код излишне сложным для чтения (как пример подкачки), и я люблю тех, которые делают код более ясным и непосредственно передающим намерение (как пример FSM).

37
ответ дан Remo.D 25 September 2017 в 20:52
поделиться
  • 1
    Спасибо Mike! Есть ли какие-либо другие переменные/пути получения отправленных данных кроме параметрических усилителей? That' s what' s действительно вызывающий меня большая часть боли. – maximus 11 June 2010 в 04:21

Я очень люблю обозначенные инициализаторы, добавленные в C99 (и поддерживаемый в gcc в течение долгого времени):

#define FOO 16
#define BAR 3

myStructType_t myStuff[] = {
    [FOO] = { foo1, foo2, foo3 },
    [BAR] = { bar1, bar2, bar3 },
    ...

инициализация массива больше не является зависимым положения. При изменении значений НЕЧТО или ПАНЕЛИ инициализация массива будет автоматически соответствовать их новому значению.

33
ответ дан DGentry 25 September 2017 в 20:52
поделиться
  • 1
    Вы знаете то, что, я узнал что я wasn' t регистрация json, that' s, почему это никогда не появлялось в параметрических усилителях. Так, Ваше решение удается очень хорошо. Еще раз спасибо! – maximus 15 June 2010 в 03:52

анонимные структуры и массивы являются моей любимой. (cf. http://www.run.montefiore.ulg.ac.be/~martin/resources/kung-f00.html )

setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));

или

void myFunction(type* values) {
    while(*values) x=*values++;
}
myFunction((type[]){val1,val2,val3,val4,0});

это может даже привыкнуть к instanciate связанным спискам...

27
ответ дан PypeBros 25 September 2017 в 20:52
поделиться
  • 1
    Извините, Вы потеряли меня немного! Как это: Замена (stringToSplit, " ([A-Z]) (? = [a-z]) | (? < = [a-z]) ([A-Z])" " \1")? – Simon 8 July 2009 в 13:33

Утверждения времени компиляции, как уже обсужденный здесь .

//--- size of static_assertion array is negative if condition is not met
#define STATIC_ASSERT(condition) \
    typedef struct { \
        char static_assertion[condition ? 1 : -1]; \
    } static_assertion_t

//--- ensure structure fits in 
STATIC_ASSERT(sizeof(mystruct_t) <= 4096);
19
ответ дан 2 revs 25 September 2017 в 20:52
поделиться
  • 1
    Хорошо, но... let' s don' t фокусируются на типе исключительной ситуации. Это является вспомогательным для базовой проблемы здесь, и поэтому я просто ввел первую вещь, которая появилась в мою голову. – Charlie Flowers 21 March 2009 в 18:14

Ну, я никогда не использовал его, и я не уверен, рекомендовал ли я когда-либо его кому-либо, но я чувствую, что этот вопрос был бы неполным без упоминания о Simon Tatham прием сопрограммы.

15
ответ дан Mark Baker 25 September 2017 в 20:52
поделиться
  • 1
    C# doesn' t поддерживают вид приемов препроцессора, которые Вы находите в компиляторах C++. – Brian Rasmussen 21 March 2009 в 19:25

Присвоение структуры прохладно. Многие люди, кажется, не понимают, что структуры являются значениями также и могут быть присвоены вокруг, нет никакой потребности использовать memcpy(), когда простое присвоение добивается цели.

, Например, рассмотрите некоторую мнимую 2D графическую библиотеку, она могла бы определить тип для представления (целочисленной) координаты экрана:

typedef struct {
   int x;
   int y;
} Point;

Теперь, Вы делаете вещи, которые могли бы выглядеть "неправильными", как запись функция, которая создает точку, инициализированную из аргументов функции, и возвращает его, как так:

Point point_new(int x, int y)
{
  Point p;
  p.x = x;
  p.y = y;
  return p;
}

Это безопасно, настолько долго (конечно), как возвращаемое значение копируется значением с помощью присвоения структуры:

Point origin;
origin = point_new(0, 0);

Таким образом можно записать довольно чистый и код объектно-ориентированного выхода, все в простом стандарте C.

12
ответ дан 2 revs 25 September 2017 в 20:52
поделиться
  • 1
    Это - точно вид вещи I' m надеющийся на, но don' t думают, что это может быть непосредственно сделано в c#. – Charlie Flowers 21 March 2009 в 18:16

Хорошо... Я думаю, что одна из сильных сторон языка C является своей мобильностью и стандартностью, поэтому каждый раз, когда я нахожу некоторый "скрытый прием", в реализации я в настоящее время использую, я пытаюсь не использовать его, потому что я пытаюсь сохранить свой код C максимально стандартным и портативным.

24
ответ дан 2 revs, 2 users 67% 25 September 2017 в 20:52
поделиться

использование INT (3) для установки точки останова в коде является моим всем фаворитом времени

8
ответ дан Dror Helper 25 September 2017 в 20:52
поделиться
  • 1
    @Jarrod, дополнительные методы статичны, таким образом, в дополнительном методе можно протестировать если ' this' цель является пустой. – ProfK 22 March 2009 в 08:04

Странная векторная индексация:

int v[100]; int index = 10; 
/* v[index] it's the same thing as index[v] */
10
ответ дан INS 25 September 2017 в 20:52
поделиться
  • 1
    Хороший. Спасибо за указание на меня там. – Charlie Flowers 23 June 2009 в 17:53

Компиляторы C реализуют один из нескольких стандартов. Однако наличие стандарта не означает, что все аспекты языка определяются. устройство Вареного пудинга , например, является фаворитом 'скрытая' функция, которая стала столь популярной, что современные компиляторы имеют код распознавания особого назначения, чтобы гарантировать, чтобы методы оптимизации не ударяли желаемый эффект этого часто используемый шаблон.

В общих скрытых функциях или приемах языка препятствуются, поскольку Вы работаете на краю бритвы того, какой бы ни стандарт (стандарты) C Ваш компилятор использует. Много таких приемов не работают от одного компилятора до другого, и часто эти виды функций перестанут работать от одной версии пакета компилятора данным производителем к другой версии.

Различные приемы, которые повредили код C, включают:

  1. Доверие, как компилятор размечает структуры в памяти.
  2. Предположения на порядок байтов из целых чисел/плаваний.
  3. Предположения на функциональном ABIs.
  4. Предположения на направлении, что стековые фреймы растут.
  5. Предположения о порядке выполнения в операторах.
  6. Предположения о порядке выполнения операторов в аргументах функции.
  7. Предположения на диаметре долота или точности коротких, международных, длинных, и двойных типов плавающих.

Другие проблемы и проблемы, которые возникают каждый раз, когда программисты делают предположения о моделях выполнения, которые все определяются в большинстве стандартов C как 'зависимое поведение' компилятора.

9
ответ дан Kevin S. 25 September 2017 в 20:52
поделиться
  • 1
    Прохладный. Какие-либо планы использовать параметрические усилители args, чтобы позволить нескольким переменным, которые будут проверены? – Charlie Flowers 7 July 2009 в 18:28

При инициализации массивов или перечислений вы можете поставить запятую после последнего элемента в списке инициализатора. например:

int x[] = { 1, 2, 3, };

enum foo { bar, baz, boom, };

Это было сделано для того, чтобы при автоматической генерации кода вам не нужно было беспокоиться об удалении последней запятой.

12
ответ дан 23 November 2019 в 23:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: