NO

Author Topic: Why is there a 'size_t' warning for "fptr1_name[i]" but not for "s2_temp[i]"?  (Read 6526 times)

colepc

  • Guest
This code will result in a 'size_t' warning for loop variable 'i' using warning level -W2:
int i;
char ch;
char fptr1_name[]="test.txt";
//get the size of the file name (will be in i)
 for(i=0,ch=' ';ch!='\0';i++)
      ch=fptr1_name;
i--; //terminator added one too many
So why is there a 'size_t' warning here?

To stop the warning I use this code:
int i;
unsigned int ui;
char ch;
char fptr1_name[]="test.txt";
//get the size of the file name (will be in i)
 for(i=0,ch=' ';ch!='\0';i++)
 {
  ui=i;
  ch=fptr1_name[ui];
 }
 i--; //terminator added one too many
Is this a good solution or is there a better one?

Why isn't there a 'size_t' warning for loop variable 'i' in this code?
int i;
//write 4 digit value to file in reverse order (MSD first - LSD last)
for(i=3;i>=0;i--)
    fputc(s2_temp,fptr2);


Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Ok, a general note first: Try get yourself acquainted with the "code" tags, that prevents such subtle mistakes as the index into the array "fptr1_name [ i ]" not showing up in the "normal" text, as it is interpreted by the forum software as the starting "italic" tag...
Quote
This code will result in a 'size_t' warning for loop variable 'i' using warning level -W2:

Code: [Select]
int i;
char ch;
char fptr1_name[]="test.txt";
//get the size of the file name (will be in i)
 for(i=0,ch=' ';ch!='\0';i++)
      ch=fptr1_name[i];
i--; //terminator added one too many
So why is there a 'size_t' warning here?
Well, my best WAG, because of bad coding habit. In a programming class, I would fail you for writing bad code.
You are using i as the loop variable, but don't define any end condition for it, instead you define the end condition depending on a different variable ch.
Beside that, even with warning level 2 (granted, I use the IDE, can't be arsed to use the command line), I do not get the warning you mentioned...
Quote
To stop the warning I use this code:
Code: [Select]
int i;
unsigned int ui;
char ch;
char fptr1_name[]="test.txt";
//get the size of the file name (will be in i)
 for(i=0,ch=' ';ch!='\0';i++)
 {
  ui=i;
  ch=fptr1_name[ui];
 }
 i--; //terminator added one too many
Is this a good solution or is there a better one?
I suspect that the overall problem here is a due to compiler optimization, due to being led on a wrong path by the way you define the for() loop.

A better solution would likely be to use a while() loop instead, with the end condition testing for the /0 character and incrementing i manually within the loop...
Quote
Why isn't there a 'size_t' warning for loop variable 'i' in this code?
Code: [Select]
int i;
//write 4 digit value to file in reverse order (MSD first - LSD last)
for(i=3;i>=0;i--)
    fputc(s2_temp[i],fptr2);
Clearly defined end condition of the loop, for all I care...

To be clear, your code isn't syntactically wrong, but is a nice example of a way how to create obfuscated code that is hard to maintain and understand, likely for the compiler as well...

Ralf

colepc

  • Guest
Bitbeisser,

There's a saying that if you don't have something nice to say then don't say anything at all. Instead of saying that someone is a bad programmer, you should either say nothing or give examples of how you would write the program so it isn't bad programming. All bad mouthing does is chase people away from this site.

You mentioned that my problem might be due to compiler optimization. Here is my 'ppj' file:
CC = pocc.exe#
AS = poasm.exe#
RC = porc.exe#
LINK = polink.exe#
SIGN = posign.exe#
CCFLAGS = -std:C11 -Tamd64-coff -Ot -Ob1 -fp:precise -W2 -Gr -Ze #
ASFLAGS = -AAMD64#
RCFLAGS = -r#
LINKFLAGS = -subsystem:windows -machine:amd64 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib delayimp64.lib oldnames64.lib#
SIGNFLAGS = -location:CU -store:MY -timeurl:http://timestamp.verisign.com/scripts/timstamp.dll -errkill#

# Build BulletSpeeds.exe.
BulletSpeeds.exe: \
   output\BulletSpeeds.res \
   output\BulletSpeeds.obj
   $(LINK) $(LINKFLAGS) -out:"$@" $**

# Build BulletSpeeds.res.
output\BulletSpeeds.res: \
   BulletSpeeds.rc \
   BulletSpeeds.ico
   $(RC) $(RCFLAGS) "$!" -Fo"$@"

# Build BulletSpeeds.obj.
output\BulletSpeeds.obj: \
   BulletSpeeds.c
   $(CC) $(CCFLAGS) "$!" -Fo"$@"

.SILENT:


Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Bitbeisser,

There's a saying that if you don't have something nice to say then don't say anything at all. Instead of saying that someone is a bad programmer, you should either say nothing or give examples of how you would write the program so it isn't bad programming. All bad mouthing does is chase people away from this site.

You mentioned that my problem might be due to compiler optimization. Here is my 'ppj' file:
Rather than getting all worked up, rather try to read and understand a post...

Sorry for trying to help you, won't happen again...

Ralf

x79

  • Guest
Here are some observations (I'm kinda new to C myself)

(*ch != '\0') == (*ch != 0) == (*ch)

The only reason I would use a for loop would be to declare a variable for the scope of the loop. AFAIK, the Pelles compiler will have the same effect as long as you don't reuse that same variable name later. You don't need to count the loop iterations to determine the size of the string. fptr1_name is a pointer to a memory address. If you get the address of its null terminator, then subtract the pointer address for the beginning of the string, you get the string length.

Here are two examples
Code: [Select]
int i = 0;    // You should initialize variables before you use them for anything
char fptr1_name[]="test.txt";

for (char ch = fptr1_name; *ch; ch++) {
    if (!(*ch))    // means the same thing as (*ch == 0) or (*ch == '\0') or (ch[0] == 0) or (ch[0] == '\0')
        i = ch - fptr1_name;    // address of ch minus address of fptr1_name
}
Code: [Select]
int i = 0;
char fptr1_name[] = "test.txt";
char *ch;
ch = fptr1_name;    // You don't have to initialize it on the same line, just do it before you use it

while (*ch)
    ch++;
i = ch - fptr1_name;

colepc

  • Guest
x79, Thanks for sharing your thoughts and code.

I tested your "while" loop code and it gave the correct answer of 8 without giving me the 'size_t' warning. I also tested your "for" loop code but unfortunately it gave me compiler errors so I changed it to be more like your "while" loop (see below). After I changed it, it also gave the correct answer of 8 without the 'size_t' warning.

My code gives the size of the string which is 9 so it had to be reduced by 1 to give the correct answer of 8. Both your code and my code try to find the location where the string terminator is located. In your case, you test for the value of 0 pointed to by a pointer and in my case I test for the character that is '\0'. According to K&R's book "The C Programming Language" on page 35 it says, "The character constant '\0' represents the character with value zero. '\0' is often written instead of 0 to emphasize the character nature of some expressions." I've often thought about using 0 instead of '\0' as 0 is so much easier to type.

There are other ways to find the number of characters in a string. I found this example on page 36 in the K&R book "The C Programming Language":
char s[]="test.txt"; //I added  ="test.txt" (the K&R example was a function returning the length of a string)
int i;
i = 0;
while ( s != '\0')
   ++i;
The "while" loop could also have been written using a "for" loop such as this:
for( i=0; s != '\0'; ++i);

The K&R "while" loop and the similar "for" loop gave me the correct answers of 8. Unfortunately, they also both gave me the 'size_t' warnings when I compiled them using my "ppj" file (previously posted). Now this is interesting. When I tested the "while" and "for" loops using a simple command prompt compiler that only has the -W2 option ("pocc -W2 Tests.c "), I did not receive the 'size_t' warning. What this means is that there is something else involved giving me 'size_t' warnings beside the -W2 "option". Perhaps the 'size_t' warning is given only when the program is compiled using 64 bits (my ppj file) and not given when compiled using 32 bits (my simple command prompt compiler). However, that doesn't explain why sometimes loop variables are not given the 'size_t' warning (Note: the example I use for no 'size_t' warning has an error, the second line should be "fputc(s2_temp,fptr2);" and not "fputc(s2_temp,fptr2);").

This is how I changed your "for" loop code:
int i = 0;    // You should initialize variables before you use them for anything
char fptr1_name[]="test.txt";
char *ch; //I added this
for (ch = fptr1_name; *ch; ch++) ; //I removed "char" and added semicolon at end
 //I removed the "if" statement
i = ch - fptr1_name;    // address of ch minus address of fptr1_name


Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
According to K&R's book "The C Programming Language"...
You are referring/relying on an at least 30 year old book, likely before even C became standardized the first time as ANSI C89 (well, in 1989, a work in progress since 1983)...

Pelle's C (and most C/C++ compiler today) adhere to the ANSI standard, with Pelle's C striving to closely follow ANSI C11 (as release in 2011)...

As I tried to tell you my first reply, not all the things that a C compiler allows is in fact good practice. Your for() loops with a terminating condition not based on the running variable is something that is bad practice. That's a well meant hint, and the errors/warnings you get if you insist on using this anyway should be another hint. It doesn't help just to increase the warning level (making the compiler make you even more aware of non-standard practices), you have to learn and act upon those warnings appropriately.

But then it seems you don't like to listen to well meant advise...

Ralf

colepc

  • Guest
Bitbeisser,

My copy of the book is copyrighted 1978 so it is closer to 40 years old. So what? It was written by Brian Kernighan and Dennis Ritchie. Dennis Ritchie developed the C language. I consider the book a great learning tool even to this day. I program only as a hobby and doubt I will ever come close to writing perfect code. But that's OK because I still enjoy making my code work even if it's terrible code. I haven't read the ANSI C89 standard nor am I interested in doing so at this time (it sounds too much like school work). You said you gave me "well meant advice" but strangely you have yet to give me an example of proper code that gives the length of a string (one that won't confuse the compiler). My guess is even you don't want to expose yourself to possible negative criticisms concerning your code writing abilities. You as a "Global Moderator" should know that giving negative criticisms can hurt others and as a "Global Moderator" you should discourage them instead of encouraging them by example.

Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Bitbeisser,

My copy of the book is copyrighted 1978 so it is closer to 40 years old. So what? It was written by Brian Kernighan and Dennis Ritchie. Dennis Ritchie developed the C language. I consider the book a great learning tool even to this day. I program only as a hobby and doubt I will ever come close to writing perfect code. But that's OK because I still enjoy making my code work even if it's terrible code. I haven't read the ANSI C89 standard nor am I interested in doing so at this time (it sounds too much like school work).
Well, that misperception on your part is the whole problem. C has changed a lot since the original K&R C, that's the whole point. C standards have been developed and changed over the years to mitigate the back choices that a programmer can make.
Software constantly evolves, all programming languages do. And if you do not evolve along with it, you will hit one roadblock after another.

Again, that is a friendly advice, so stop seeing this as "negative criticism" and try to throw blame in the other direction...

Ralf

defrancis7

  • Guest
Eventually Classical C, also known as K & R C, (after its creators), will NOT be supported by the ANSI standard.  For example:  the string function gets(*char); which is now deprecated.   Just saying...

Dee

Snowman

  • Guest
As part of the learning process, you are now reinventing the wheel instead of just using strlen() from string.h.
Keep in mind that you need to save some time and energy to learn more important things:

http://c-faq.com/

I haven't read the ANSI C89 standard nor am I interested in doing so at this time (it sounds too much like school work).
I don't think anybody wants you to read the C89 standard document, which is basically Legalese for compiler and standard library implementers (to help them create C89 standard compliant tools). Also you should focus on C99 instead, because it has more features than C89 and is all around better.

So you don't need to do "school work", just visit these links (of course after you mastered the basics):

http://en.cppreference.com/w/c
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=215