2012-06-27 2 views
1

Я новичок в C и хочу знать, правильно ли я обрабатываю что-то. Я создаю модуль для http://nginx.com/, и я создаю страницу состояния для моего модуля.Расчет размера строки C перед записью в буфер

Теперь страница состояния будет состоять из некоторых базовых таблиц HTML &. Вот некоторые из моего кода, чтобы создать это.

// Get size 
size = 
    sizeof("<table>") + 
    sizeof("<tr><td align=\"right\">enabled:</td><td>YES</td></tr>") + 
    sizeof("<tr><td align=\"right\">activated:</td><td>YES</td></tr>") + 
    sizeof("<tr><td align=\"right\">connections/lt:</td><td>") + NGX_ATOMIC_T_LEN + sizeof("/") + NGX_ATOMIC_T_LEN + sizeof("</td></tr>") + 
    sizeof("<tr><td align=\"right\">remain on: xxxx-xx-xx xx:xx:xx GMT</td><td></td></tr>") + 
    sizeof("</table>"); 

// Start buffer 
b = ngx_create_temp_buf(r->pool, size); 
if (b == NULL) { 
    return NGX_HTTP_INTERNAL_SERVER_ERROR; 
} 

// Start chain 
out.buf = b; 
out.next = NULL; 

// Finish buffer 
b->last = ngx_sprintf(b->last, "<table>"); 
b->last = ngx_sprintf(b->last, "<tr><td align=\"right\">enabled:</td><td>%s</td></tr>", alcf->enabled ? "YES" : "NO"); 
b->last = ngx_sprintf(b->last, "<tr><td align=\"right\">activated:</td><td>%s</td></tr>", alcf->activated ? "YES" : "NO"); 
b->last = ngx_sprintf(b->last, "<tr><td align=\"right\">connections/lt:</td><td>%uA/%uA</td></tr>", ac, alcf->connections_activate); 
b->last = ngx_sprintf(b->last, "<tr><td align=\"right\">remain on:</td><td>"); 
b->last = !alcf->activatedEndTime ? ngx_sprintf(b->last,"") : ngx_http_cookie_time(b->last, alcf->activatedEndTime); 
b->last = ngx_sprintf(b->last, "</td></tr>"); 
b->last = ngx_sprintf(b->last, "<table>"); 

Это единственный эффективный способ сделать это, я чувствую, что это было бы неправильно, чтобы написать HTML код дважды, один раз, чтобы получить размер, чтобы раздуть буфер, и один на самом деле хранить в буфер. Будет ли какое-то другое решение. Я стараюсь держать его как можно более эффективным.

+0

http://stackoverflow.com/questions/5338446/predict-len-of-an-sprintf-ed-line –

ответ

1

Я думаю, что у вас есть ошибка «один за другим» - вы забыли оставить место для завершения \0.

Ваше использование sizeof работает, но заставляет вас повторять каждую часть HTML. Однажды вы обновите HTML в строках sprintf и забудете обновить копию в строках sizeof, что приведет к переполнению памяти.

Лучшим способом было бы сохранить строки один раз и использовать strlen для получения размеров.
Вот пример идеи. Это далеко не идеальный, но он сохраняет большую часть повторения.

struct html_part { 
    const char *text; 
    size_t extra_len; 
}; 
struct html_part html_parts[] = { 
    { "<table>", 0 } 
    { "<tr><td align=\"right\">enabled:</td><td>%s</td></tr>", 3-2 } // YES=3, %s=2 
    ... 
}; 
// Calculate the space needed 
len = 0; 
for (i=0;i<sizeof(html_parts)/sizeof(html_parts[0]);i++) { 
    len += strlen(html_parts[i].text) + html_parts[i].extra_len; 
} 
len++; // For the terminating null 
... 
// Print the data 
b->last = ngx_sprintf(b->last, html_parts[0]); 
b->last = ngx_sprintf(b->last, html_parts[1], alcf->enabled ? "YES" : "NO"); 
+0

Это отличная идея и именно то, что я искал, спасибо! – arosolino

3

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

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

+0

Спасибо, просто не хотел продолжать писать больше, если он не был прав. – arosolino