سؤال

I'm looking to find the length of a C-string literal at compile time. Given the definitions:

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]);

How do I find the length of string literal header_left[2] without using strlen?

In this question, Determining the Length of a String Literal, there is a comment to declare the array as header_left[][4]. I prefer not to use this kind of declaration as there is a tendency for the number of strings to change without changing the quantity constant. I like having the compiler calculate the quantity of strings (see the rows_in_header definition) and the length of each string.

This is for an embedded system and the strings are block written to a serial port. The serial port function takes a pointer to the data and the length of the data as parameters. The serial port code is optimized for block writes. The preference is not to use strlen because that wastes performance time.

I am using C99 with IAR Embedded Workshop on an ARM7TDMI platform.
I have included the c++ tag because this also involves C++ and we will be migrating the code to C++ after first product launch.

هل كانت مفيدة؟

المحلول 2

Actually the advice in the linked answer is wrong. as it has the indexes reversed. The declaration should be more along the lines of this:

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

The left-most index can still be provided by the compiler, and indicates the count of strings. The strings themselves must be a fixed char array, which you could provide an upper bound on (40, in this example). You'll get a compile-error if any string exceeds that length (including null terminator). The potential downside for your purposes is wasted space.

In any event, you can't have the compiler deduce both sizes for you - that of both arrays - and jagged arrays aren't supported in C++.

نصائح أخرى

A stringref class can handle this if you desire. It seems simpler than most other answers, and handles situtations where the rows are different lenghts:

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

Macro magic! (>= C99) Requires at least 2 rows.

Note I don't use char const* but char const[...] here, i.e. arrays, because it's possible and guarantees all rows have the same length.

Edit: subtracted -1 from length_of_row to get rid of the '\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]) yields the length of the first string (row)
  • static const char header_left[][length_of_row] is an unbounded array of arrays of length_of_row char; same as typedef char const row[length_of_row]; row header_left[] = {...};

You can extract the header_left[2] string and use 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;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top