I think I may miss your meaning. In what sense is .size or length() not "free?"
At some point, some O(n) work was done somewhere to construct the n-element structure we're getting size on, but I don't think I've ever encountered a core library that implements .size as anything other than "Look up the cached length value that I computed the last time my length changed."
I think I just gave away the game on how long it's been since I programmed in C itself. Even C++ has "free" length() in std::string (in the sense that it's specified that it must be a constant-time operation).
... that's actually a good example of the trap of thinking of C as "what's really going on." If you assume C's treatment of char* is how strings have to be done, you're out of alignment with basically all other programming languages and you might be writing unnecessarily slow code (or forcing developers using your code to juggle a homegrown "length" abstraction that the underlying language should be juggling for them).
At some point, some O(n) work was done somewhere to construct the n-element structure we're getting size on, but I don't think I've ever encountered a core library that implements .size as anything other than "Look up the cached length value that I computed the last time my length changed."