Search code examples
cbenchmarking

Why is string literal faster than a static char array?


I ran a following test.

charspeed.c

#include <stdio.h>
#include <time.h>

#define CHAR_COUNT 26
#define CHAR_LIST "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
static const char *CHAR_ARRAY = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

#define RUN_COUNT 1000000000

#define GET_CLOCK (float)clock() / CLOCKS_PER_SEC

int main()
{
    long long int sum = 0;
    float start, end;

    start = GET_CLOCK;
    for (size_t i = 0; i < RUN_COUNT; i++)
    {
        char test = CHAR_LIST[i % CHAR_COUNT];
        sum += test; // Force the loop to run!
    }
    end = GET_CLOCK;
    printf("#define Time: %f\n", end - start);

    start = GET_CLOCK;
    for (size_t i = 0; i < RUN_COUNT; i++)
    {
        char test = CHAR_ARRAY[i % CHAR_COUNT];
        sum += test; // Must be the same as fist loop!
    }
    end = GET_CLOCK;
    printf("static const *CHAR_ARRAY Time: %f\n", end - start);
    printf("sum = %lld\n", sum); // Must access "sum" after loops!
    return 0;
}

Its outputs

#define Time: 1.741000
static const *CHAR_ARRAY Time: 1.868000

Why the string literal using #define directive faster than a pre-initialised static char array? Where exactly the string literal is stored and why it is faster to access them within a block scop?

The compiler option used is gcc -o charspeed charspeed.c


Solution

  • Note: Edited to 'synchronize' with OP's changes:

    Maybe the problem is that you aren't giving a good enough test. A decent compiler will run both loops in zero time, because nothing of consequence happens inside them. I tried on MSVC, and your code gave 0 for both times.

    However, increasing the loop counts ten-fold and putting in something that can't be optimized away, I get pretty much equal times for both:

    #include <stdio.h>
    #include <time.h>
    
    #define CHAR_COUNT 26
    #define CHAR_LIST "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    static const char* CHAR_ARRAY = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
    #define RUN_COUNT 1000000000 // Increased by factor of 10!
    #define GET_CLOCK (double)clock() / CLOCKS_PER_SEC
    
    int main()
    {
        long long int sum = 0;
        double start, end;
    
        start = GET_CLOCK;
        for (size_t i = 0; i < RUN_COUNT; i++) {
            char test = CHAR_LIST[i % CHAR_COUNT];
            sum += test; // Force the loop to run!
        }
        end = GET_CLOCK;
        printf("#define Time: %lf\n", end - start);
    
        start = GET_CLOCK;
        for (size_t i = 0; i < RUN_COUNT; i++) {
            char test = CHAR_ARRAY[i % CHAR_COUNT];
            sum += test; // Must be the same as fist loop!
        }
        end = GET_CLOCK;
        printf("static const *CHAR_ARRAY Time: %lf\n", end - start);
        printf("sum = %lld\n", sum); // Must access "sum" after loops!
        return 0;
    }
    

    Try doing something like this on your compiler/machine, to see if it makes a difference.