Home > Back-end >  Is there an efficient way to get the length of a global static string in C?
Is there an efficient way to get the length of a global static string in C?

Time:03-26


#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static const char doc_type_tag[] = "<!DOCTYPE html>\n";


int main()
{

    return 0;
}

I have a global string, and I realize sizeof (doc_type_tag) / sizeof (doc_type_tag[0]); is not valid.

Is there any other way other than strlen?

CodePudding user response:

I'm puzzled by your assertion:

I realize sizeof (doc_type_tag) / sizeof (doc_type_tag[0]); is not valid.

Given that the variable has file scope but its visibility is restricted to this file, the array definition is fully visible and the size is defined in full.

The rules would be a bit different if there were multiple source files and this file had extern char doc_type_tag[]; and not the actual array definition — with the initialization.

But with the array definition there, the sizeof expression works fine. It also works for char doc_type_tag[] = "<!DOCTYPE html>\n" because the complete array definition is visible.

Of course, you also have to fix the position of the array brackets.

Code

#include <stdio.h>

static const char doc_type_tag[] = "<!DOCTYPE html>\n";
enum { DOC_TYPE_TAG_SZ = sizeof(doc_type_tag) / sizeof(doc_type_tag[0]) };

const char html_tag[] = "<html>";
enum { HTML_TAG_SZ = sizeof(html_tag) / sizeof(html_tag[0]) };

int main(void)
{
    size_t sz_doc_type_tag = sizeof(doc_type_tag) / sizeof(doc_type_tag[0]);
    printf("%zu (%d) [%s]\n", sz_doc_type_tag, DOC_TYPE_TAG_SZ, doc_type_tag);
    size_t sz_html_tag = sizeof(html_tag) / sizeof(html_tag[0]);
    printf("%zu (%d) [%s]\n", sz_html_tag, HTML_TAG_SZ, html_tag);
    return 0;
}

Note that the enumeration values are of type int and not size_t, hence the different conversion specifications.

Output:

17 (17) [<!DOCTYPE html>
]
7 (7) [<html>]

Pointers

If the declaration was:

 static const char *doc_type_tag = "<!DOCTYPE html>\n";

then we'd be in a very different discussion — there isn't a way to find out the length of the string pointed at by doc_type_tag except by using strlen() or something equivalent to it, not least because although what it points at when the program starts is clear enough, it could be reassigned to point somewhere else by the time its value is used. And the sizeof(doc_type_tag) / sizeof(doc_type_tag[0]) expression would usually evaluate to 8 (or 4 if you're using a 32-bit compilation), because that's the size of the pointer. Pointers are not arrays, especially in the context of sizeof.

Main program: as31.c

Here's a multi-file variation on the code above:

#include <stdio.h>
#include <string.h>
#include "xml.h"

static const char doc_type_tag[] = "<!DOCTYPE html>";
enum { DOC_TYPE_TAG_SZ = sizeof(doc_type_tag) / sizeof(doc_type_tag[0]) };

const char html_tag[] = "<html>";
enum { HTML_TAG_SZ = sizeof(html_tag) / sizeof(html_tag[0]) };

int main(void)
{
    size_t sz_doc_type_tag = sizeof(doc_type_tag) / sizeof(doc_type_tag[0]);
    printf("%zu (%d) [%s]\n", sz_doc_type_tag, DOC_TYPE_TAG_SZ, doc_type_tag);
    size_t sz_html_tag = sizeof(html_tag) / sizeof(html_tag[0]);
    printf("%zu (%d) [%s]\n", sz_html_tag, HTML_TAG_SZ, html_tag);
    size_t sz_xml_decl_tag = sizeof(xml_decl_tag) / sizeof(xml_decl_tag[0]);
    printf("%zu (%d) [%s]\n", sz_xml_decl_tag, XML_DECL_TAG_SZ, xml_decl_tag);

    //size_t sz_pqr_tag = sizeof(pqr_tag) / sizeof(pqr_tag[0]);
    //enum { PQR_TAG_SZ = sizeof(pqr_tag) / sizeof(pqr_tag[0]) };

    printf("%zu [%s]\n", strlen(pqr_tag)   1, pqr_tag);
    return 0;
}

Note that the sizeof games simply don't work on pqr_tag, declared in xml.h and defined in xml.c. (I also removed the newline from the doc_type_tag initializer.)

Header file: xml.h

extern char xml_decl_tag[56];
enum { XML_DECL_TAG_SZ = sizeof(xml_decl_tag) / sizeof(xml_decl_tag[0]) };

extern char pqr_tag[];

Definition file: xml.c

char xml_decl_tag[56] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";

char pqr_tag[] = "<another tag>";

Output

16 (16) [<!DOCTYPE html>]
7 (7) [<html>]
56 (56) [<?xml version="1.0" encoding="UTF-8" standalone="yes"?>]
14 [<another tag>]

CodePudding user response:

  • In case of an array const char doc_type_tag[] = "...":

    sizeof (doc_type_tag) / sizeof (doc_type_tag[0])       // size of array
    (sizeof (doc_type_tag) / sizeof (doc_type_tag[0]) - 1) // string length
    
  • In case of a pointer char* doc_type_tag = "...":

    #define INITIALIZER "<!DOCTYPE html>\n"
    const char* doc_type_tag = INITIALIZER;
    ...
    sizeof(INITIALIZER)       // size of array
    (sizeof(INITIALIZER) - 1) // string length
    
  • Related