1

我希望在编译时找到 C 字符串文字的长度。给定定义:

static const char * const   header_left[] =
{
    "         |          |  Raw  |  Raw  |",
    "         |          | Start |  End  |",
    "Interval#| Duration | Point | Point |",
    "---------+----------+-------+-------+",
};
const unsigned int  rows_in_header = sizeof(header_left) / sizeof(header_left[0]);

如何在header_left[2]不使用的情况下找到字符串文字的长度strlen

在这个问题中,Determining the Length of a String Literal中,有一条注释将数组声明为header_left[][4]。我不喜欢使用这种声明,因为字符串的数量倾向于在不改变数量常数的情况下发生变化。我喜欢让编译器计算字符串的数量(参见rows_in_header定义)和每个字符串的长度。

这适用于嵌入式系统,字符串被块写入串行端口。串口函数将指向数据的指针和数据的长度作为参数。串行端口代码针对块写入进行了优化。首选是不使用strlen,因为这会浪费性能时间。

我在 ARM7TDMI 平台上使用 C99 和 IAR Embedded Workshop。
我已包含该c++标签,因为这也涉及 C++,我们将在首次产品发布后将代码迁移到 C++。

4

4 回答 4

4

如果您愿意,一个 stringref 类可以处理这个问题。它似乎比大多数其他答案更简单,并且可以处理行长度不同的情况:

struct stringref {
    //this is for convenience, but isn't used in this sample
    stringref(const char* p, size_t l=0) :ptr(p), len(l?l:strlen(p)) {}
    //construct from string literals
    template<size_t l> stringref(const char(&p)[l]) :ptr(p), len(l) {}
    //convert to const char*
    operator const char*() const {return ptr;}
    const char* get() const {return ptr;}
    //retrieve the length
    size_t length() const {return len;}
private:
    const char* ptr;
    size_t len;
};

stringref header_left[] =
{
    "         |          |  Raw  |  Raw  |   ",
    "         |          | Start |  End  | ",
    "Interval#| Duration | Point | Point |      ",
    "---------+----------+-------+-------+",
};

int main()
{
    const char* ptr = header_left[0]; //conversion possible
    printf("%d\n", header_left[0].length());
    printf("%d\n", header_left[1].length());
    printf("%d\n", header_left[2].length());
    printf("%d\n", header_left[3].length());
}

http://coliru.stacked-crooked.com/view?id=e244267379f84e21409db9ec39da5765-50d9cfc8a1d350e7409e81e87c2653ba

于 2013-05-01T18:42:06.777 回答
1

实际上,链接答案中的建议是错误的。因为它的索引反转了。声明应该更符合以下内容:

static const char header_left[][40] =
{
    "         |          |  Raw  |  Raw  |",
    "         |          | Start |  End  |",
    "Interval#| Duration | Point | Point |",
    "---------+----------+-------+-------+",
};

最左边的索引仍然可以由编译器提供,并指示字符串的计数。字符串本身必须是一个固定的 char 数组,您可以提供一个上限(在本例中为 40)。如果任何字符串超过该长度(包括空终止符),您将收到编译错误。您的目的的潜在缺点是浪费空间。

无论如何,您不能让编译器为您推断出两种大小——两个数组的大小——并且 C++ 不支持锯齿状数组。

于 2013-05-01T18:09:36.223 回答
1

宏观魔术!(>= C99) 至少需要 2 行。

注意我在这里不使用char const*but char const[...],即数组,因为它是可能的并且保证所有行都具有相同的长度。

编辑:减去 -1length_of_row以摆脱'\0'.

#include<cstddef>
#define CREATE_HEADER(X, ...) \
  static const size_t length_of_row = sizeof(X)/sizeof(X[0]) - 1; \
  static const char header_left[][length_of_row+1] = { X, __VA_ARGS__ }; \
  static const size_t rows_in_header = sizeof(header_left) / sizeof(header_left[0]); \

CREATE_HEADER(
    "         |          |  Raw  |  Raw  |",
    "         |          | Start |  End  |",
    "Interval#| Duration | Point | Point |",
    "---------+----------+-------+-------+",
);

  • sizeof(X)/sizeof(X[0])产生第一个字符串(行)的长度
  • static const char header_left[][length_of_row]length_of_row是char数组的无界数组;如同typedef char const row[length_of_row]; row header_left[] = {...};
于 2013-05-01T18:16:36.813 回答
0

您可以提取header_left[2]字符串并使用sizeof(...) - 1

static const char header_left_2[] = "Interval#| Duration | Point | Point |";
static const char * const   header_left[] =
{
    "         |          |  Raw  |  Raw  |",
    "         |          | Start |  End  |",
    header_left_2,
    "---------+----------+-------+-------+",
};
const unsigned int  rows_in_header = sizeof(header_left) / sizeof(header_left[0]);
const size_t header_left_2_len = sizeof(header_left_2) - 1;
于 2013-05-01T18:14:58.980 回答