sizeof and strlen()

  • Thread starter Bill Cunningham
  • Start date
B

Bill Cunningham

Does strlen() not return it's size_t if the data is uninitialized ? And
sizeof does it work with initialized and uninitialized data?

For example,

ssize_t recv(int s, void *buf, size_t len, int flags);

char buf[1024];

recv(sock,buf,strlen(buf),0);

^
notice this parameter of the function returns size_t. Would it help if I
used char buf[1024]={0}; ?

Bill
 
T

Tom St Denis

    Does strlen() not return it's size_t  if the data is uninitialized ? And
sizeof does it work with initialized and uninitialized data?

    For example,

ssize_t recv(int s, void *buf, size_t len, int flags);

    char buf[1024];

recv(sock,buf,strlen(buf),0);

                         ^
notice this parameter of the function returns size_t. Would it help if I
used char buf[1024]={0}; ?

I think what it is you found a bug in glibc and should report it right
away to the maintainers. This is clearly a very severe issue.

Tom
 
B

Bill Cunningham

Tom said:
I think what it is you found a bug in glibc and should report it right
away to the maintainers. This is clearly a very severe issue.

Very funny.

B
 
L

Lew Pitcher

Does strlen() not return it's size_t if the data is uninitialized ?

strlen() always returns a size_t value, whether argument points at an
initialized area or not.

strlen() accepts a pointer to a character array which contains a string in C
format (terminated with a '\0' (0) character), and returns the length of
that string. strlen() does *not* return the length of an arbitrary
character buffer.

If the pointer you give as the argument to strlen() points to character
array, initialized with a string, strlen() will return a count of the
number of significant characters in the string. Technically, it returns a
count of characters between the start of the string (the pointer's value)
and the first '\0' (0) character.

If the pointer you give as the argument to strlen() points to character
array that is *not* initialized with a string, the results of strlen() are
unpredictable and likely incorrect. This is because there is no guarantee
that the character array pointed to contains the sentinal '\0' (0)
character in /any/ position.

If the pointer you give as the argument to strlen() points to an
uninitialized array, the results of strlen() are unpredictable and likely
incorrect. This is because there is no guarantee that the character array
pointed to contains the sentinal '\0' (0) character in /any/ position.
And
sizeof does it work with initialized and uninitialized data?

sizeof evaluates to the size (in characters) of it's argument. It works
whether the argument is initialized or not.


strlen() and sizeof are two different facilities, with two different
purposes. Please don't confuse them.

For example,

ssize_t recv(int s, void *buf, size_t len, int flags);

char buf[1024];

recv(sock,buf,strlen(buf),0);

^
notice this parameter of the function returns size_t.
So?

Would it help if I
used char buf[1024]={0}; ?

No, it wouldn't.

Bill, you still have a fundamental misunderstanding about strlen() and
sizeof, and about function arguments for specific functions.

As I pointed out above, strlen() and sizeof are two different facilities,
with two different purposes.

sizeof is evaluated once, when you compile your program.
sizeof evaluates to the size of it's argument, in characters
sizeof is handy when you want to substitute, at compile time, a value that
represents the fixed length of an object.

strlen() is evaluated, possibly many times, when you run your program.
strlen() counts the number of char elements between the start of an array
and the first '\0' (0) byte in the array. This count does not have to
relate /at all/ to the size of the array.
strlen() is handy when you want to know how big a C string is.

To illustrate the differences, I'll use a code fragment.....

First, let's allocate a character array object and initialize it
with a string

char buf[1024] = "My buffer";

Notice that the character array object (<buf>) is 1024 characters long,
and that it contains a string ("My buffer") which is 10 characters long,
including the terminating '\0'.

Let's also allocate a couple of size_t objects:

size_t bufSizeof,
bufStrlen;

Now, let's put some values into thes two size_t objects:

bufSizeof = sizeof buf;
bufStrlen = strlen(buf);

If we look at these two values, we see that
- bufSizeof is set to 1024, representing the total number of characters
allocated to buf, and
- bufStrlen is set to 9, representing the 9 significant characters of the
string "My buffer", stored in buf

Follow me so far?

So we have strlen() to find out how big a *string* is, and sizeof to find
out how big an *object* is.

Now, on to your recv() function call.....

Using your prototype for recv()

ssize_t recv(int s, void *buf, size_t len, int flags);

and the relevant documentation (recv() is outside of ISO C, and it's
documentation is found elsewhere), we find that the argument <len>
specifies the length (in characters) of the buffer <buf>. Further, we find
that recv() will, if successful, place no more than <len> characters of new
data into <buf>.

You have an object
char buf[1024];
and want recv() to put data into that object. You need to tell recv() /how
much/ data to put into <buf>. The *most* you can ask recv() to put into
<buf> is (sizeof buf). You can ask for less, of course, but strlen() is not
an appropriate function (in this example) to determine /how much/ data
recv() should put in <buf>, because your argument to strlen() *doesn't
contain a string*.

To make it simple, until you become more familiar with C, POSIX, sockets,
and all those other areas of programming that you are exploring, you ALWAYS
want

char buf[1024];

recv(sock,buf,sizeof buf,0);


HTH
 
K

Keith Thompson

Bill Cunningham said:
Does strlen() not return it's size_t if the data is uninitialized ? And
sizeof does it work with initialized and uninitialized data?

For example,

ssize_t recv(int s, void *buf, size_t len, int flags);

char buf[1024];

recv(sock,buf,strlen(buf),0);

^
notice this parameter of the function returns size_t. Would it help if I
used char buf[1024]={0}; ?

A string is a '\0'-terminated sequence of characters. Are you
working with strings here? No. Then why would you even consider
using strlen()?
 
B

Bill Cunningham

Keith said:
A string is a '\0'-terminated sequence of characters. Are you
working with strings here? No. Then why would you even consider
using strlen()?

Then I've been reading some really bad code lately. This was not my idea
to use strlen but the code I was reading used it. Should one use numbers
such as simply 1024 as int not char* and I put +1 to my code too for the \0.
I don't know why the author used strlen unless it was because of the size_t.

Bill
 
B

Bill Cunningham

Then I've been reading some really bad code lately. This was not my
idea to use strlen but the code I was reading used it. Should one use
numbers such as simply 1024 as int not char* and I put +1 to my code too
for the \0. I don't know why the author used strlen unless it was because
of the size_t.

I can't find out where I was reading this but this is a page I've been
getting alot from-

http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#sendrecv
 
L

Lew Pitcher

I can't find out where I was reading this but this is a page I've been
getting alot from-

http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#sendrecv

A search through that page shows that /nowhere/ in the code or explanations
does Beej indicate to use strlen() to set the length on the recv() call. In
fact, Beej either explicitly sets the length (one or two examples) or uses
sizeof to specify the length in those recv() calls.

However, Beej /does/ use strlen() at least once, in an example of the
*send()* call. And, there, it makes sense, as his example wants to send()
only the significant characters of a string, and not the entire contents of
the character array that the string sits in.

Are you certain that you haven't confused the examples of the send() call
with the examples of the recv() call?
 
B

Bill Cunningham

Lew said:
A search through that page shows that /nowhere/ in the code or
explanations does Beej indicate to use strlen() to set the length on
the recv() call. In fact, Beej either explicitly sets the length (one
or two examples) or uses sizeof to specify the length in those recv()
calls.

However, Beej /does/ use strlen() at least once, in an example of the
*send()* call. And, there, it makes sense, as his example wants to
send() only the significant characters of a string, and not the
entire contents of the character array that the string sits in.

Are you certain that you haven't confused the examples of the send()
call with the examples of the recv() call?

It is quite possible and probable that I have confused send() and recv()
parameters. There is no other website I draw more on than his so I would say
I confused recv() for send(). My apologizes. I will read more carefully and
watch my quoting other's work.

Bill
 
K

Keith Thompson

Bill Cunningham said:
Then I've been reading some really bad code lately. This was not my idea
to use strlen but the code I was reading used it. Should one use numbers
such as simply 1024 as int not char* and I put +1 to my code too for the \0.
I don't know why the author used strlen unless it was because of the size_t.

No, you've just been failing to understand the code you're reading.

The author used strlen because he wanted to compute the length *of a
string*. He didn't use it "because of the size_t"; he used it because
it was the correct tool for the job.

Choose which function or operator to use on the basis of what it does
and whether that meets your requirement, not just on the basis of what
type it returns.

Don't guess.
 
B

Bill Cunningham

Lew said:
Are you certain that you haven't confused the examples of the send()
call with the examples of the recv() call?

Right where you cut and pasted I noticed something I don't quite
understand.

Beej says:
int send(int sockfd, const void *msg, int len, int flags);
sockfd is the socket descriptor you want to send data to (whether it's the
one returned by socket() or the one you got with accept().) msg is a pointer
to the data you want to send, and len is the length of that data in bytes.
Just set flags to 0. (See the send() man page for more information
concerning flags.)

Some sample code might be:

char *msg = "Beej was here!";
int len, bytes_sent;
..
..
..
len = strlen(msg);
bytes_sent = send(sockfd, msg, len, 0);
..
..
end quote.len has been declared an int and Beej has strlen passing value to
it.But strlen returns a size_t. That's the thing I don't understand about
send().Bill
 
B

Bill Cunningham

Keith said:
No, you've just been failing to understand the code you're reading.

The author used strlen because he wanted to compute the length *of a
string*. He didn't use it "because of the size_t"; he used it because
it was the correct tool for the job.

I see.
Choose which function or operator to use on the basis of what it does
and whether that meets your requirement, not just on the basis of what
type it returns.

Don't guess.

This turns upside down some of my beliefs about functions and return
types. BTW I am still using quote-fix and I'm hoping the quoting is better.

Bill
 
K

Keith Thompson

Bill Cunningham said:
I see.


This turns upside down some of my beliefs about functions and return
types. BTW I am still using quote-fix and I'm hoping the quoting is better.

I'm having trouble figuring out what those beliefs might have been. Did
you think that you could look *only* at what type a function returns and
decide that it's the right thing? If you were writing mathematical
software, how would you decide whether to use sin() or sqrt()?

Please note that I wrote "not *JUST* on the basis of what type it
reuturns".
 
K

Keith Thompson

Bill Cunningham said:
Beej says:
int send(int sockfd, const void *msg, int len, int flags);
sockfd is the socket descriptor you want to send data to (whether it's the
one returned by socket() or the one you got with accept().) msg is a pointer
to the data you want to send, and len is the length of that data in bytes.
Just set flags to 0. (See the send() man page for more information
concerning flags.)

Some sample code might be:

char *msg = "Beej was here!";
int len, bytes_sent;
.
.
.
len = strlen(msg);
bytes_sent = send(sockfd, msg, len, 0);
.
.
end quote.

len has been declared an int and Beej has strlen passing value to
it.But strlen returns a size_t. That's the thing I don't understand about
send().Bill

Look at your system's documentation for send(). What is the type
of its third parameter?

Are you writing calls to functions without reading their
documentation first? For the sake of everybody's time and sanity,
stop doing that.

In any case, both int and size_t are integer types. If you pass
a value of one type to a function expecting an argument of the
other type, it will be implicitly converted. It's likely to be
poor style, but as long as it's within the range of both, there's
(probably) no problem.
 
B

Bill Cunningham

Keith said:
I'm having trouble figuring out what those beliefs might have been.
Did you think that you could look *only* at what type a function
returns and decide that it's the right thing? If you were writing
mathematical software, how would you decide whether to use sin() or
sqrt()?

That would be easy. They both return doubles. So if you came across a
function like this,

double math(double operator);

Then sqrt() or sin() would work. Now if you came across this,

double math(int operator);

I don't think you can do this,

math(sqrt(5));

because math takes a double as parameter. It wants something that is going
to return a double not just an int. The int isn't big enough.

Bill
 
K

Keith Thompson

Bill Cunningham said:
Keith Thompson wrote: [...]
I'm having trouble figuring out what those beliefs might have been.
Did you think that you could look *only* at what type a function
returns and decide that it's the right thing? If you were writing
mathematical software, how would you decide whether to use sin() or
sqrt()?

That would be easy. They both return doubles. So if you came across a
function like this,

double math(double operator);

Then sqrt() or sin() would work.

Either you're trolling, or you've completely missed my point.

Suppose you're writing code that needs to perform some mathematical
operation.

Question: How do you decide, at a certain point in the code,
whether to call sqrt() or sin()?

Answer: Call sqrt() if you need to compute a square root; call sin() if
you need to compute a trigonometric sine.

[snip]
 
B

Bill Cunningham

Keith Thompson wrote:

[...]
Question: How do you decide, at a certain point in the code,
whether to call sqrt() or sin()?

Answer: Call sqrt() if you need to compute a square root; call sin()
if you need to compute a trigonometric sine.

[snip]

Oh I thought we were talking about return values.

Bill
 
T

Tom St Denis

Strlen does it's work at run-time.
Sizeof does it's work at compile time.

Not true. Consider:

#include <stdio.h>

int blah(int a) { int buf[a]; return sizeof buf; }
int main(void) { printf("%d\n", blah(10)); return 0; }

It's valid C99 code and should print out 40 on [most] 32-bit hosts.

Tom
 
I

Ian Collins

Strlen does it's work at run-time.
Sizeof does it's work at compile time.

Not true. Consider:

#include<stdio.h>

int blah(int a) { int buf[a]; return sizeof buf; }
int main(void) { printf("%d\n", blah(10)); return 0; }

It's valid C99 code and should print out 40 on [most] 32-bit hosts.

Also consider

#include <string.h>

void f( size_t );

int main()
{
const char* p = "hello world";

f( strlen( p ) );

return 0;
}

A decent compiler will optimise "strlen( p )" to 11.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,527
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top