Ваш формат printf неправильный и вызывает UB.
Абстрагируясь от математической логики вашей функции.
void sqrtNR(double num)
{
printf ("\nnum: %f\n", num);
x = num;
printf ("x: %f\n", x);
while(var < fabs(f(x,num))
{
x = x - ( f(x,num)/g(x,num) );
}
return x;
}
Вы также должны поместить параметры макроса в круглые скобки
C99 предлагает некоторый действительно интересный материал с помощью анонимных массивов:
Удаляющие бессмысленные переменные
{
int yes=1;
setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}
становятся
setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));
Передача Переменной Суммы Аргументов
void func(type* values) {
while(*values) {
x = *values++;
/* do whatever with x */
}
}
func((type[]){val1,val2,val3,val4,0});
Статические связанные списки
int main() {
struct llist { int a; struct llist* next;};
#define cons(x,y) (struct llist[]){{x,y}}
struct llist *list=cons(1, cons(2, cons(3, cons(4, NULL))));
struct llist *p = list;
while(p != 0) {
printf("%d\n", p->a);
p = p->next;
}
}
Любой, который я уверен много других прохладных методов, о которых я не думал.
Я думаю использование userdata , указатели круты. Вид, теряющий позиции в наше время. Это не так функция C, но довольно просто в использовании в C.
Я использую X-макросы к позволить предварительному компилятору сгенерировать код. Они особенно полезны для определения ошибочных значений и связанных строк ошибки в одном месте, но они могут пойти далеко вне этого.
Наша кодовая база имеет прием, подобный
#ifdef DEBUG
#define my_malloc(amt) my_malloc_debug(amt, __FILE__, __LINE__)
void * my_malloc_debug(int amt, char* file, int line)
#else
void * my_malloc(int amt)
#endif
{
//remember file and line no. for this malloc in debug mode
}
, который допускает отслеживание утечек памяти в режиме отладки. Я всегда думал, что это было прохладно.
Вот пример, как заставить C кодировать completly не зная о том, что на самом деле используется HW для того, чтобы запустить приложение. main.c делает установку, и затем бесплатный слой может быть реализован на любом компиляторе/дуге. Я думаю, что это довольно аккуратно для абстракции C, кодируют немного, таким образом, это не добирается, чтобы быть к определенному.
Добавление полного компилируемого примера здесь.
/* free.h */
#ifndef _FREE_H_
#define _FREE_H_
#include <stdio.h>
#include <string.h>
typedef unsigned char ubyte;
typedef void (*F_ParameterlessFunction)() ;
typedef void (*F_CommandFunction)(ubyte byte) ;
void F_SetupLowerLayer (
F_ParameterlessFunction initRequest,
F_CommandFunction sending_command,
F_CommandFunction *receiving_command);
#endif
/* free.c */
static F_ParameterlessFunction Init_Lower_Layer = NULL;
static F_CommandFunction Send_Command = NULL;
static ubyte init = 0;
void recieve_value(ubyte my_input)
{
if(init == 0)
{
Init_Lower_Layer();
init = 1;
}
printf("Receiving 0x%02x\n",my_input);
Send_Command(++my_input);
}
void F_SetupLowerLayer (
F_ParameterlessFunction initRequest,
F_CommandFunction sending_command,
F_CommandFunction *receiving_command)
{
Init_Lower_Layer = initRequest;
Send_Command = sending_command;
*receiving_command = &recieve_value;
}
/* main.c */
int my_hw_do_init()
{
printf("Doing HW init\n");
return 0;
}
int my_hw_do_sending(ubyte send_this)
{
printf("doing HW sending 0x%02x\n",send_this);
return 0;
}
F_CommandFunction my_hw_send_to_read = NULL;
int main (void)
{
ubyte rx = 0x40;
F_SetupLowerLayer(my_hw_do_init,my_hw_do_sending,&my_hw_send_to_read);
my_hw_send_to_read(rx);
getchar();
return 0;
}
Две хороших исходных книги для этого вида материала Практика Программирования и , Пишущего Твердый Код . Один из них (я не помню, который), говорит: Предпочтите перечисление #define, где Вы можете, потому что перечисление проверяется компилятор.
Ржавый на самом деле произвел полный набор условных выражений сборки в ccan, проверьте сборку, утверждают модуль:
#include <stddef.h>
#include <ccan/build_assert/build_assert.h>
struct foo {
char string[5];
int x;
};
char *foo_string(struct foo *foo)
{
// This trick requires that the string be first in the structure
BUILD_ASSERT(offsetof(struct foo, string) == 0);
return (char *)foo;
}
существует много других полезных макросов в фактическом заголовке, которое легко заскочить в место.
я пробую со всей моей силой для сопротивления получению по запросу темной стороны (и злоупотребление препроцессора), придерживаясь главным образом подставляемых функций, но я действительно наслаждаюсь умными, полезными макросами как те, Вы описали.
Этот происходит из книги флаг 'Enough rope to shoot yourself in the foot ':
In the header declare
#ifndef RELEASE
# define D(x) do { x; } while (0)
#else
# define D(x)
#endif
In your code place testing statements eg:
D(printf("Test statement\n"));
The do/while helps in case the contents of the macro expand to multiple statements.
The statement will only be printed if '-d RELEASE' для компилятора, не используется.
Вы можете тогда, например, передать флаг своему make-файлу и т.д.
Не уверенный, как это работает в окнах, но в *отклоняют его работы хорошо
Если мы говорим о приемах c, мой фаворит должен быть Устройство Вареного пудинга для развертывания цикла! Я просто ожидаю правильной возможности прийти, чтобы я на самом деле использовал ее в гневе...
Я люблю использование = {0};
для инициализации структур, не будучи должен назвать memset.
struct something X = {0};
Это инициализирует всех членов структуры (или массив) для обнуления (но не любые дополнительные байты - используют memset, если необходимо обнулить их также).
, Но необходимо знать, что существует некоторые проблемы с этим для больших, динамично выделенных структур .
В C99
typedef struct{
int value;
int otherValue;
} s;
s test = {.value = 15, .otherValue = 16};
/* or */
int a[100] = {1,2,[50]=3,4,5,[23]=6,7};
использование __FILE__
и __LINE__
для отладки
#define WHERE fprintf(stderr,"[LOG]%s:%d\n",__FILE__,__LINE__);
Объектно-ориентированный код с C, путем эмуляции классов.
Просто создают структуру и ряд функций, которые берут указатель на ту структуру как первый параметр.
Как только мой помощник и я переопределили возврат для нахождения хитрой ошибки повреждения стека.
Что-то как:
#define return DoSomeStackCheckStuff, return
Мне нравится "взлом структуры" за то, что он имел динамично размерный объект. Этот сайт объясняет это вполне прилично также (хотя они обращаются к версии C99, где можно записать "ул. []" как последний член структуры). Вы могли сделать строку "объектом" как это:
struct X {
int len;
char str[1];
};
int n = strlen("hello world");
struct X *string = malloc(sizeof(struct X) + n);
strcpy(string->str, "hello world");
string->len = n;
здесь, мы выделили структуру типа X на "куче", которая является размером интервала (для len), плюс длина "привет мира", плюс 1 (так как ул. 1 включена в sizeof (X).
обычно полезно, когда Вы хотите иметь "заголовок" прямо перед некоторыми данными переменной длины в том же блоке.
Используя глупый макро-прием для создания рекордных определений легче поддержать.
#define COLUMNS(S,E) [(E) - (S) + 1]
typedef struct
{
char studentNumber COLUMNS( 1, 9);
char firstName COLUMNS(10, 30);
char lastName COLUMNS(31, 51);
} StudentRecord;
Сдвиги разряда только определяются до shift-amount 31 (на целом числе на 32 бита)..
, Что Вы делаете, если Вы хотите иметь вычисленный сдвиг, который должен работать с более высоким shift-values также? Вот то, как смотри-кодек Theora делает это:
unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
return (a>>(v>>1))>>((v+1)>>1);
}
Или намного более читаемый:
unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
unsigned int halfshift = v>>1;
unsigned int otherhalf = (v+1)>>1;
return (a >> halfshift) >> otherhalf;
}
Выполнение задачи путь, показанный выше, намного быстрее, чем использование ответвления как это:
unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
if (v<=31)
return a>>v;
else
return 0;
}
Для создания переменной, которая только для чтения во всех модулях кроме того, в котором оно объявляется:
// Header1.h:
#ifndef SOURCE1_C
extern const int MyVar;
#endif
<час> // Source1.c:
#define SOURCE1_C
#include Header1.h // MyVar isn't seen in the header
int MyVar; // Declared in this file, and is writeable
<час> // Source2.c
#include Header1.h // MyVar is seen as a constant, declared elsewhere
Объявление массива указателя на функции для реализации конечных автоматов.
int (* fsm[])(void) = { ... }
самое приятное преимущество состоит в том, что просто вынудить каждый стимул/состояние проверить все пути выполнения кода.
Во встроенной системе, я буду часто отображать ISR, чтобы указать на такую таблицу и повторно векторизовать ее по мере необходимости (вне ISR).
Другой хороший препроцессор "прием" должен использовать "#" символ для печати выражений отладки. Например:
#define MY_ASSERT(cond) \
do { \
if( !(cond) ) { \
printf("MY_ASSERT(%s) failed\n", #cond); \
exit(-1); \
} \
} while( 0 )
редактирование: код ниже только работает над C++. Благодаря smcameron и Evan Teran.
Да, время компиляции утверждает, является всегда большим. Это может также быть записано как:
#define COMPILE_ASSERT(cond)\
typedef char __compile_time_assert[ (cond) ? 0 : -1]
Я действительно не назвал бы это любимым приемом, так как я никогда не использовал его, но упоминание об Устройстве Вареного пудинга напомнило мне о эта статья о реализации Сопрограмм в C. Это всегда дает мне хихиканье, но я уверен, что это могло быть полезно некоторое время.
#if TESTMODE == 1
debug=1;
while(0); // Get attention
#endif
, в то время как (0); не имеет никакого эффекта на программу, но компилятор выйдет, предупреждение об "этом не делает ничего", которого является достаточно, чтобы заставить меня пойти посмотреть на незаконную строку и затем видеть настоящие основания, я хотел привлечь внимание к нему.
Мне нравится концепция container_of
используется, например, в списках. По сути, вам не нужно указывать поля следующее
и последнее
для каждой структуры, которая будет в списке. Вместо этого вы добавляете заголовок структуры списка к фактическим связанным элементам.
Посмотрите на include / linux / list.h
реальные примеры.
Читая исходный код Quake 2, я придумал что-то вроде этого:
double normals[][] = {
#include "normals.txt"
};
(более или менее, у меня нет кода, чтобы проверить это сейчас
С тех пор перед моими глазами открылся новый мир творческого использования препроцессора. Я больше не включаю только заголовки, а время от времени включаю целые фрагменты кода (это значительно улучшает возможность повторного использования) :-p
Спасибо, Джон Кармак! xD
Я не знаю, является ли это прием. Но когда я был юниором в университете мой друг, и я завершал лабораторию в нашем вводном курсе C++. Мы должны были взять имя человека и использовать для своей выгоды его, отобразить его назад и затем дать им опцию отображения их имени "в последний раз, сначала". Для этой лаборатории нам мешали использовать нотацию массива.
Он показал мне этот код, я думал, что это была самая прохладная вещь, которую я видел в то время.
char * ptr = "first name";
//flies to the end of the array, regardless of length
while( *ptr++ );