3

is there some trick to define a constant string literal without a trailing '\0' character?

#define ARRAY_LEN(array) (sizeof(array)/sizeof((array)[0]))

static const char c_seqence[] = "___----__--_-_";

So that using ARRAY_LEN(c_seqence) returns the actual sequence length without the '\0'? No runtime ovearhead should be generated. Obiously the string like representation is preffered to a char array {'_','_',...} initialization because of better readability.

C solution is preffered but may be also some c++ solution may be interesting as long they do not rely on c++11 features.

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80
  • 2
    `#define ARRAY_LEN(array) (sizeof(array)/sizeof((array)[0]) - 1);` :P – Jonathan Potter Mar 18 '15 at 23:17
  • I was going to say `#define STR_LEN(array) (ARRAY_LEN(array) - 1)`. LOL. – Austin Mullins Mar 18 '15 at 23:18
  • You shouldn't be using a macro for this anyway. http://stackoverflow.com/questions/437150/can-someone-explain-this-template-code-that-gives-me-the-size-of-an-array – Brian Bi Mar 18 '15 at 23:19
  • Never mind, I didn't catch the "C solution is preferred". – Brian Bi Mar 18 '15 at 23:21
  • @JonathanPotter Why was that not worth posting as an answer rather then a comment. – Clifford Mar 18 '15 at 23:22
  • @Clifford, because he didn't answer the actual question – Fatih BAKIR Mar 18 '15 at 23:22
  • @Clifford A lot of times I'll post short answers in comments to see the OP's initial reaction before posting a real answer. – Austin Mullins Mar 18 '15 at 23:23
  • @JonathanPotter Thanks :). This perfectly answeres the question in a pure logical sense but clearly was not the intention but it made me smile. – vlad_tepesch Mar 18 '15 at 23:26
  • @FatihBAKIR : It may not satisfy *"some trick to define a constant string literal without a trailing '\0'*, to which the answer is just no if you exclude the array initialisation syntax; but it does address *"So that using ARRAY_LEN(c_seqence) returns the actual sequence length without the '\0'?"*, so is the only useful answer, and it is not a *comment*. Moreover the answer appears to be acceptable to the OP, but he cannot *accept* a comment. – Clifford Mar 18 '15 at 23:28
  • Technically, `boost::mpl::string` is not C++11 and lets you do four characters at once (`<'abcd', 'efgh'>`). It has `size` and `c_str` metafunctions. – chris Mar 18 '15 at 23:30
  • I didn't think my comment would actually answer the OPs question, which was about modifying the string literal itself. – Jonathan Potter Mar 18 '15 at 23:31
  • 1
    @JonathanPotter : If an answer gets harshly down-voted, you can always delete it if such things worry you. Even if the answer is not accepted by the OP, it may be of interest to someone seeking similar solutions. The comments are not searchable on SO so are of less community value. – Clifford Mar 18 '15 at 23:33
  • Ok, answered. I better get lots of rep now! :) – Jonathan Potter Mar 18 '15 at 23:43

3 Answers3

5

Is there some trick to define a constant string literal without a trailing '\0' character?

In C, if you specify the size of a character array to be one less than the size of the string literal initializer, it won't have a trailing null character. You could do it like so:

static const char c_seqence[ARRAY_LEN("___----__--_-_")-1] = "___----__--_-_";

Of course, to avoid having to indicate the string literal twice in the same line, you might want to define a macro to do it:

#define MAKE_STR_LITERAL(n, l) static const char n[ARRAY_LEN(l)-1] = l

You can use it like this:

MAKE_STR_LITERAL(c_seqence, "___----__--_-_");

Note:

As stated in https://stackoverflow.com/a/4348188/2793118, this behavior is in section 6.7.8 of the standard (quoting from that answer):

§ 6.7.8p14

An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

Note2: Turns out this is a C-only thing. In C++ it will not compile. Yet another great example of why people shouldn't tag questions with both C and C++.

Community
  • 1
  • 1
Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • if i define a `static const char c_a[5] = "12345";` then i get a compiler warning/error: `Error 1 initializer-string for array of chars is too long [-fpermissive] ` – vlad_tepesch Mar 18 '15 at 23:28
  • @vlad_tepesch Hum, that's odd. This - http://ideone.com/bcg2zP - compiles without any warning even if I use `-Wall` in my machine. I'm almost sure this is somewhere in the standard, let me look that up. – Filipe Gonçalves Mar 18 '15 at 23:31
  • @vlad_tepesch Please see my updated answer. As I suspected, it's in the standard, so you shouldn't get any errors / warnings. What compiler are you using? – Filipe Gonçalves Mar 18 '15 at 23:37
  • AVR8/GNU C Compiler : 4.8.1 – vlad_tepesch Mar 18 '15 at 23:39
  • @FilipeGonçalves, `if (x = 2)` is also standard, but very commonly gives a warning. – chris Mar 18 '15 at 23:43
  • 4
    @vlad_tepesch Hum, this is different in C and C++. Turns out this is a C-only thing. C++ compilers will give you this error. Great example of why you shouldn't tag a question with C and C++ :) – Filipe Gonçalves Mar 18 '15 at 23:44
  • ups right, i renamed the file to cpp to test something ;) – vlad_tepesch Mar 18 '15 at 23:50
  • 4
    `MAKE_STR_LITERAL` is a poor name for a macro that makes an array which doesn't contain a string and isn't a literal – M.M Mar 19 '15 at 00:00
2

The simplest solution is to change your array length macro to ignore the trailing null:

#define ARRAY_LEN(array) (sizeof(array)/sizeof((array)[0]) - 1)

(posted under duress :)

Jonathan Potter
  • 36,172
  • 4
  • 64
  • 79
  • obviously this is not the intendet way to solve this. since some kind of `ARRAY_LEN` macro is a commonly used idiom, its meaning/definition should not be changed. – vlad_tepesch Mar 18 '15 at 23:54
  • 1
    #define STRING_LEN(array) (ARRAY_LEN(array) - 1) – andrewrk Mar 18 '15 at 23:57
  • 1
    I'd suggest calling it something different to `ARRAY_LEN` which indicates that it doesnt actually give the length of an array – M.M Mar 19 '15 at 00:03
0

In C++11, without macros:

template <typename T, size_t n>
constexpr size_t array_length(const T (&)[n]) {
    return n;
}

template <typename T, size_t n>
constexpr size_t string_length(const T (&)[n]) {
    return n - 1;
}

I realize the question explicitly eliminates C++11 but that might not be true about everyone reaching this question from a search engine.

andrewrk
  • 30,272
  • 27
  • 92
  • 113
  • may be if c++11 may be used, someone could define its own type prefix. but iam not fully aware of the possibilities and restrictions of such a solution atm – vlad_tepesch Mar 18 '15 at 23:55