在堆栈上分配大小的字符串缓冲区的好方法是什么?

时间:2015-12-09 17:59:16

标签: c

使用纯C(和C预处理器)我想创建一个包含长度参数的字符串缓冲区,这样我就可以轻松地传递它,任何在其上运行的函数都可以这样做而不会有写过去的危险结束。这很简单:

typedef struct strbuf_t_ {
    int  length;
    char str[1];
} strbuf_t;

但是如果我想在堆栈上使用一个小的空间来格式化一些输出文本,那么在堆栈上分配strbuf_t并不是一种简单的方法。我想要的是一些允许我这样做的聪明的宏:

STRBUF(10) foo;
printf("foo.length = %d\n", foo.length); // outputs: foo.length = 10
strncpy(foo.str, "this is too long", foo.length);

不幸的是,我似乎无法做到这一点。我提出的最好的是:

#define STRBUF(size, name) \
    struct {\
        strbuf_t buf;\
        char space[size - 1];\
        char zero;\
    } name ## _plus_space_ = { .buf={.length=size}, .space="", .zero='\0'};\
    strbuf_t *name = &name ## _plus_space_.buf

int main(void)
{
    STRBUF(10, a);

    strncpy(a->str, "Hello, world!", a->length);
    printf("a->length = %d\n", a->length); // outputs: a->length = 10
    puts(a->str); // outputs: Hello, wor
}

这符合我列出的所有要求,但a是一个指针,而不是结构本身,分配肯定不直观。

有没有人想出更好的东西?

2 个答案:

答案 0 :(得分:1)

我认为你已经非常接近解决方案了。只需在结构中保留function MyCtrl($scope, $rootScope) { $rootScope.name = 'Superhero'; } function ChildCtrl($scope, $rootScope) { $rootScope.debug = ''; $scope.$watch('name', function(newVal, oldVal) { $scope.debug += " value changed..."; }); } 并通过char-array分配它。为了在字符串的末尾保存尾随零,只需为该大小分配一个额外的字符,并用零初始化整个数组。

char*

答案 1 :(得分:1)

也许如下。使用对齐的VLA分配内存,然后重叠。

typedef struct strbuf_t_ {
    int  length;
    char str[];
} strbuf_t;

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdalign.h>

int main(void) {
  char *s = "Hello";

  size_t length = strlen(s);
  size_t n = sizeof (strbuf_t) + length + 1;
  _Alignas(strbuf_t) unsigned char mem[n];

  strbuf_t *xx = (strbuf_t*) mem;
  xx->length = length;
  memcpy(xx->str, s, n+1);

  printf("int:%zu s:%zu n:%zu mem:%zu\n", 
      sizeof xx->length, sizeof (strbuf_t), n, sizeof mem);
  return 0;
}

输出

int:4 s:4 n:6 mem:10

注意:C99允许最后struct成员的无限数组计数为[]