Discussion:
unsigned char
(too old to reply)
Bill Cunningham
2014-08-16 23:40:47 UTC
Permalink
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this mbr
offset. Would the proper declaration and code be,

unsigned char string[8]="MSWIN4.1";

It looks good to me.

Bill
Lynn McGuire
2014-08-16 23:54:20 UTC
Permalink
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this mbr
offset. Would the proper declaration and code be,
unsigned char string[8]="MSWIN4.1";
It looks good to me.
Bill
That is nine bytes with the null terminator.

Lynn
Ben Bacarisse
2014-08-17 00:10:15 UTC
Permalink
Post by Lynn McGuire
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this mbr
offset. Would the proper declaration and code be,
unsigned char string[8]="MSWIN4.1";
It looks good to me.
Bill
That is nine bytes with the null terminator.
sizeof string == 8 and the initialisation does not put a null byte into
the array -- i.e. there is no out-of-bounds access. The name of the
array is rather deceptive, because it does not contain a string in the C
sense of the word, precisely because it is not null terminated.
--
Ben.
Bill Cunningham
2014-08-17 01:06:19 UTC
Permalink
Post by Ben Bacarisse
Post by Lynn McGuire
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this mbr
offset. Would the proper declaration and code be,
unsigned char string[8]="MSWIN4.1";
It looks good to me.
Bill
That is nine bytes with the null terminator.
sizeof string == 8 and the initialisation does not put a null byte into
the array -- i.e. there is no out-of-bounds access. The name of the
array is rather deceptive, because it does not contain a string in the C
sense of the word, precisely because it is not null terminated.
It should be BS_OEMName to be exact. I just looked it up.

Bill
Bill Cunningham
2014-08-17 05:01:43 UTC
Permalink
Post by Lynn McGuire
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this mbr
offset. Would the proper declaration and code be,
unsigned char string[8]="MSWIN4.1";
It looks good to me.
Bill
That is nine bytes with the null terminator.
I ran a small program that printed to stdout (null) for the 8th byte of
the char string and I got a segmentation fault when I ran the program that
would print the 8th byte of the unsigned char string.

Bill
Barry Schwarz
2014-08-17 05:29:08 UTC
Permalink
On Sun, 17 Aug 2014 01:01:43 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Lynn McGuire
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this mbr
offset. Would the proper declaration and code be,
unsigned char string[8]="MSWIN4.1";
It looks good to me.
Bill
That is nine bytes with the null terminator.
I ran a small program that printed to stdout (null) for the 8th byte of
the char string and I got a segmentation fault when I ran the program that
would print the 8th byte of the unsigned char string.
Show your code.
--
Remove del for email
Bill Cunningham
2014-08-18 18:30:19 UTC
Permalink
Post by Barry Schwarz
Show your code.
I think I figure out my bug. In printing out one value being name[8].
The last charater I used in the printf format specifier %s instead if %c by
habit. Would that do it?

Bill
Kaz Kylheku
2014-08-18 19:06:59 UTC
Permalink
Post by Bill Cunningham
Post by Barry Schwarz
Show your code.
I think I figure out my bug.
That will be a first in fifteen years! Shall we bring out the champagne?
Richard Heathfield
2014-08-18 19:35:31 UTC
Permalink
Post by Bill Cunningham
Post by Barry Schwarz
Show your code.
I think I figure out my bug. In printing out one value being name[8].
The last charater I used in the printf format specifier %s instead if %c
by habit. Would that do it?
No.

Show your code.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Bill Cunningham
2014-08-18 20:35:21 UTC
Permalink
Post by Barry Schwarz
Post by Bill Cunningham
Post by Barry Schwarz
Show your code.
I think I figure out my bug. In printing out one value being name[8].
The last charater I used in the printf format specifier %s instead if %c
by habit. Would that do it?
No.
Show your code.
#include <stdio.h>

int main()
{
unsigned char BS_OEMName[8] = "MSWIN4.1";
char BS_OEMName2[8] = "MSWIN4.1";
printf("%s\n%s\n", BS_OEMName[8], BS_OEMName2[8]);
return 0;
}
Richard Heathfield
2014-08-18 20:44:11 UTC
Permalink
Bill Cunningham wrote:

<snip>
Post by Bill Cunningham
#include <stdio.h>
int main()
{
unsigned char BS_OEMName[8] = "MSWIN4.1";
This is an array of unsigned char, with eight elements. The offsets of those
elements are 0 through 7.
Post by Bill Cunningham
char BS_OEMName2[8] = "MSWIN4.1";
Same here.
Post by Bill Cunningham
printf("%s\n%s\n", BS_OEMName[8], BS_OEMName2[8]);
If it existed, BS_OEMName[8] would be an unsigned char, not a string, so %s
is not the right format specifier for it. Since it doesn't exist, trying to
access it is a memory bounds violation. The same applies for BS_OEMName2[8],
except that it would be a char rather than an unsigned char (if it existed).

The right way to print a single character is with %c. If you want to print
strings, %s is fine, but you need to pass to printf a pointer to the first
character in the string. Unfortunately, you don't have strings, since
neither of your arrays is null-terminated.

If you want strings, specify enough storage to allow for a null terminator,
or allow C to provide the size automatically:

unsigned char BS_OEMName[] = "MSWIN4.1";
char BS_OEMName2[] = "MSWIN4.1";
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Bill Cunningham
2014-08-18 20:57:04 UTC
Permalink
Post by Richard Heathfield
<snip>
Post by Bill Cunningham
#include <stdio.h>
int main()
{
unsigned char BS_OEMName[8] = "MSWIN4.1";
This is an array of unsigned char, with eight elements. The offsets of those
elements are 0 through 7.
Post by Bill Cunningham
char BS_OEMName2[8] = "MSWIN4.1";
Same here.
Post by Bill Cunningham
printf("%s\n%s\n", BS_OEMName[8], BS_OEMName2[8]);
If it existed, BS_OEMName[8] would be an unsigned char, not a string, so %s
is not the right format specifier for it. Since it doesn't exist, trying to
access it is a memory bounds violation. The same applies for
BS_OEMName2[8],
except that it would be a char rather than an unsigned char (if it existed).
The right way to print a single character is with %c. If you want to print
strings, %s is fine, but you need to pass to printf a pointer to the first
character in the string. Unfortunately, you don't have strings, since
neither of your arrays is null-terminated.
If you want strings, specify enough storage to allow for a null terminator,
unsigned char BS_OEMName[] = "MSWIN4.1";
char BS_OEMName2[] = "MSWIN4.1";
That's exactly what I thought. My first mistake was by habit using the
%s instead of %c. But you know when I tried %c on both of these there was
some weird garbage that printed out.
Anyway the MBR and docs I'm looking at declare a specific offset and
room for 8 bytes.

http://home.teleport.com/~brainy/fatgen102.pdf

Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size? It's
a string "MSWIN4.1"

Bill
Bill Cunningham
2014-08-18 21:01:02 UTC
Permalink
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.

Bill
Keith Thompson
2014-08-18 21:30:29 UTC
Permalink
Post by Bill Cunningham
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.
What "rest of the bits"?

How many bits in a char? (8, almost certainly)

How many characters long is "MSWIN4.1"? (8, since in this case there's
no terminating '\0' null character)

If you have 64 bits (8 bytes) to play with, and you've already used 8
bytes (64 bits) to store "MSWIN4.1", how many more bits would be
available for padding? (none)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Bill Cunningham
2014-08-18 21:45:53 UTC
Permalink
Post by Keith Thompson
Post by Bill Cunningham
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.
What "rest of the bits"?
How many bits in a char? (8, almost certainly)
How many characters long is "MSWIN4.1"? (8, since in this case there's
no terminating '\0' null character)
If you have 64 bits (8 bytes) to play with, and you've already used 8
bytes (64 bits) to store "MSWIN4.1", how many more bits would be
available for padding? (none)
Oh yes that's right. I don't know what I'm thinking. I was thinking that
whole string was 1 byte. No the CHAR is 1 byte or 8 bits. I'm not thinking
as usual. Well anyway I hope that link shows what I'm looking at. It's not a
complete MBR that I see. Only 80 some bytes. And my machine has two tools to
dump. A hexdump and a hexeditor. The MBR signature is displayed by one as
0xAA55 and the other as 0x55AA. So I am not quite sure what my machine is in
Endianness.

Bill


Bill
Barry Schwarz
2014-08-19 04:20:03 UTC
Permalink
On Mon, 18 Aug 2014 17:45:53 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Keith Thompson
Post by Bill Cunningham
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.
What "rest of the bits"?
How many bits in a char? (8, almost certainly)
How many characters long is "MSWIN4.1"? (8, since in this case there's
no terminating '\0' null character)
If you have 64 bits (8 bytes) to play with, and you've already used 8
bytes (64 bits) to store "MSWIN4.1", how many more bits would be
available for padding? (none)
Oh yes that's right. I don't know what I'm thinking. I was thinking that
whole string was 1 byte. No the CHAR is 1 byte or 8 bits. I'm not thinking
as usual. Well anyway I hope that link shows what I'm looking at. It's not a
complete MBR that I see. Only 80 some bytes. And my machine has two tools to
dump. A hexdump and a hexeditor. The MBR signature is displayed by one as
0xAA55 and the other as 0x55AA. So I am not quite sure what my machine is in
Endianness.
Find a tool that will display the contents of the sector in bytes, not
in two byte chunks.

Which two bytes are you looking at? According to the web page you
reference, the first byte should be either 0xE9 or 0xEB. Since
neither one of your displays satisfies this requirement, you might be
looking at the wrong data.

If you want to determine the endianness of your machine, try the
following program

#include <stdio.h>
int main(void){
unsigned int x = 0x12345678;
unsigned char *p = (char*)&x;
int i;
for (i = 0; i < sizeof x; i++)
printf("%x ", p[i]);
putchar('\n');
return 0;
}

If the hex values display in ascending order, you machine is
big-endian. If they display in descending order, the machine is
little-endian. If they display in any other order, you mistyped the
program and should use cut and paste.
--
Remove del for email
Richard Damon
2014-08-19 12:37:19 UTC
Permalink
Post by Barry Schwarz
On Mon, 18 Aug 2014 17:45:53 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Keith Thompson
Post by Bill Cunningham
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.
What "rest of the bits"?
How many bits in a char? (8, almost certainly)
How many characters long is "MSWIN4.1"? (8, since in this case there's
no terminating '\0' null character)
If you have 64 bits (8 bytes) to play with, and you've already used 8
bytes (64 bits) to store "MSWIN4.1", how many more bits would be
available for padding? (none)
Oh yes that's right. I don't know what I'm thinking. I was thinking that
whole string was 1 byte. No the CHAR is 1 byte or 8 bits. I'm not thinking
as usual. Well anyway I hope that link shows what I'm looking at. It's not a
complete MBR that I see. Only 80 some bytes. And my machine has two tools to
dump. A hexdump and a hexeditor. The MBR signature is displayed by one as
0xAA55 and the other as 0x55AA. So I am not quite sure what my machine is in
Endianness.
Find a tool that will display the contents of the sector in bytes, not
in two byte chunks.
Which two bytes are you looking at? According to the web page you
reference, the first byte should be either 0xE9 or 0xEB. Since
neither one of your displays satisfies this requirement, you might be
looking at the wrong data.
If you want to determine the endianness of your machine, try the
following program
#include <stdio.h>
int main(void){
unsigned int x = 0x12345678;
unsigned char *p = (char*)&x;
int i;
for (i = 0; i < sizeof x; i++)
printf("%x ", p[i]);
putchar('\n');
return 0;
}
If the hex values display in ascending order, you machine is
big-endian. If they display in descending order, the machine is
little-endian. If they display in any other order, you mistyped the
program and should use cut and paste.
Small correction,
Little Endian won't display in a strictly descending order (87654321)
but as 78563412 (least byte to high byte) if char is 8 bits, and int is
32 bits.
Ben Bacarisse
2014-08-19 13:05:41 UTC
Permalink
<snip>
Post by Richard Damon
Post by Barry Schwarz
If you want to determine the endianness of your machine, try the
following program
#include <stdio.h>
int main(void){
unsigned int x = 0x12345678;
unsigned char *p = (char*)&x;
int i;
for (i = 0; i < sizeof x; i++)
printf("%x ", p[i]);
putchar('\n');
return 0;
}
<snip>
Post by Richard Damon
Small correction,
Little Endian won't display in a strictly descending order (87654321)
but as 78563412 (least byte to high byte) if char is 8 bits, and int
is 32 bits.
For which reason I think it's simpler to use:

unsigned int x = 0x01020304;
--
Ben.
Bill Cunningham
2014-08-19 18:49:10 UTC
Permalink
Post by Barry Schwarz
Which two bytes are you looking at? According to the web page you
reference, the first byte should be either 0xE9 or 0xEB. Since
neither one of your displays satisfies this requirement, you might be
looking at the wrong data.
The data I am talking about with 0xAA55 or 0x55AA is the end signature of a
master boot record. It has nothing to do with the link I posted. The bast 2
bytes of sector 63 on a HD.

Bill
Bill Cunningham
2014-08-19 19:45:01 UTC
Permalink
"Richard Damon" <***@Damon-Family.org> wrote in message news:6yHIv.12581$***@fx01.iad...

[snip]
Post by Richard Damon
Small correction,
Little Endian won't display in a strictly descending order (87654321)
but as 78563412 (least byte to high byte) if char is 8 bits, and int is 32
bits.
Thanks for your input Richard. This is what my machine displayed.

78 56 34 12

I hope that's what you intended. With that putchar() in there. So I guess
this is ascending order? Looks like it. Now was that the original
"endianess" of the old IBM PCs?

Bill
Barry Schwarz
2014-08-20 04:00:55 UTC
Permalink
On Tue, 19 Aug 2014 15:45:01 -0400, "Bill Cunningham"
Post by Bill Cunningham
[snip]
Post by Richard Damon
Small correction,
Little Endian won't display in a strictly descending order (87654321)
but as 78563412 (least byte to high byte) if char is 8 bits, and int is 32
bits.
Thanks for your input Richard. This is what my machine displayed.
78 56 34 12
I hope that's what you intended. With that putchar() in there. So I guess
this is ascending order? Looks like it. Now was that the original
"endianess" of the old IBM PCs?
How on earth can you say with a straight face that numbers which
decrease are in ascending order?

If your machine actually displayed that, then it is little endian.

If you want to know the endianness of some ancient machine, you need
to get one and test it?
--
Remove del for email
Richard Heathfield
2014-08-20 07:09:15 UTC
Permalink
Post by Barry Schwarz
On Tue, 19 Aug 2014 15:45:01 -0400, "Bill Cunningham"
<snip>
Post by Barry Schwarz
Post by Bill Cunningham
78 56 34 12
I hope that's what you intended. With that putchar() in there. So I guess
this is ascending order? Looks like it. Now was that the original
"endianess" of the old IBM PCs?
How on earth can you say with a straight face that numbers which
decrease are in ascending order?
Perhaps he's an Australian. Everybody knows they walk around on their heads
all day.

The trick with Bill is always to remember that he won't listen to anything
you say or, even if by some miracle he does, he'll have forgotten it by
tomorrow (or even by this afternoon).

In any reply to Bill, always try to include at least one detail that may be
useful to other readers. Because it sure as heck won't do Bill the slightest
bit of good.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Barry Schwarz
2014-08-20 03:50:59 UTC
Permalink
On Tue, 19 Aug 2014 08:37:19 -0400, Richard Damon
Post by Richard Damon
Post by Barry Schwarz
On Mon, 18 Aug 2014 17:45:53 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Keith Thompson
Post by Bill Cunningham
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.
What "rest of the bits"?
How many bits in a char? (8, almost certainly)
How many characters long is "MSWIN4.1"? (8, since in this case there's
no terminating '\0' null character)
If you have 64 bits (8 bytes) to play with, and you've already used 8
bytes (64 bits) to store "MSWIN4.1", how many more bits would be
available for padding? (none)
Oh yes that's right. I don't know what I'm thinking. I was thinking that
whole string was 1 byte. No the CHAR is 1 byte or 8 bits. I'm not thinking
as usual. Well anyway I hope that link shows what I'm looking at. It's not a
complete MBR that I see. Only 80 some bytes. And my machine has two tools to
dump. A hexdump and a hexeditor. The MBR signature is displayed by one as
0xAA55 and the other as 0x55AA. So I am not quite sure what my machine is in
Endianness.
Find a tool that will display the contents of the sector in bytes, not
in two byte chunks.
Which two bytes are you looking at? According to the web page you
reference, the first byte should be either 0xE9 or 0xEB. Since
neither one of your displays satisfies this requirement, you might be
looking at the wrong data.
If you want to determine the endianness of your machine, try the
following program
#include <stdio.h>
int main(void){
unsigned int x = 0x12345678;
unsigned char *p = (char*)&x;
int i;
for (i = 0; i < sizeof x; i++)
printf("%x ", p[i]);
putchar('\n');
return 0;
}
If the hex values display in ascending order, you machine is
big-endian. If they display in descending order, the machine is
little-endian. If they display in any other order, you mistyped the
program and should use cut and paste.
Small correction,
Little Endian won't display in a strictly descending order (87654321)
but as 78563412 (least byte to high byte) if char is 8 bits, and int is
32 bits.
The code I posted would display 78 56 34 12 which seems strictly
descending to me.
--
Remove del for email
Barry Schwarz
2014-08-18 21:47:43 UTC
Permalink
On Mon, 18 Aug 2014 17:01:02 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.
Since you did not show how you defined the array, what makes you think
there are any bits after the 64 bits that are used in the array of 8
characters?
--
Remove del for email
Bill Cunningham
2014-08-18 23:43:42 UTC
Permalink
Post by Barry Schwarz
Since you did not show how you defined the array, what makes you think
there are any bits after the 64 bits that are used in the array of 8
characters?
All I know is that MSWIN4.1 is wanted in a 8 bytes space. What to do
about '\0' I do not know. Unless one would use the type unsigned int and
simply used an array of 8 elements. No '\0' would be needed. The document
says nothing about char types though everything is in C. But does mention
unsigned ints. I saw the quotes and what was in them and assumed this was a
string and still believe it should because certain drivers look at this.

Bill


Bill
Barry Schwarz
2014-08-19 03:55:55 UTC
Permalink
On Mon, 18 Aug 2014 19:43:42 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Barry Schwarz
Since you did not show how you defined the array, what makes you think
there are any bits after the 64 bits that are used in the array of 8
characters?
All I know is that MSWIN4.1 is wanted in a 8 bytes space. What to do
about '\0' I do not know. Unless one would use the type unsigned int and
simply used an array of 8 elements. No '\0' would be needed. The document
says nothing about char types though everything is in C. But does mention
unsigned ints. I saw the quotes and what was in them and assumed this was a
string and still believe it should because certain drivers look at this.
Why are you making assumptions? There is no mystery. There is
nothing hidden. There are no surprises. There is no guessing.

Look up the definition of a string in any of your C references and
describe in what way you think the 8 character array initialized to
"MSWIN4.1" satisfies that definition. Once you convince yourself that
it does not satisfy the definition, then it obviously cannot be a
string.

Why should the fact that some C code references the array influence
your determination of whether the array contains a string or not? Have
you bothered to look at how the code references the array? Does the
code assume the array contains a string? Does the code use any
functions that would invoke undefined behavior if the array does not
contain a string?

Your belief is does not follow from your premise.
--
Remove del for email
Bill Cunningham
2014-08-19 18:51:05 UTC
Permalink
Post by Barry Schwarz
On Mon, 18 Aug 2014 19:43:42 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Barry Schwarz
Since you did not show how you defined the array, what makes you think
there are any bits after the 64 bits that are used in the array of 8
characters?
All I know is that MSWIN4.1 is wanted in a 8 bytes space. What to do
about '\0' I do not know. Unless one would use the type unsigned int and
simply used an array of 8 elements. No '\0' would be needed. The document
says nothing about char types though everything is in C. But does mention
unsigned ints. I saw the quotes and what was in them and assumed this was a
string and still believe it should because certain drivers look at this.
Why are you making assumptions? There is no mystery. There is
nothing hidden. There are no surprises. There is no guessing.
Look up the definition of a string in any of your C references and
describe in what way you think the 8 character array initialized to
"MSWIN4.1" satisfies that definition. Once you convince yourself that
it does not satisfy the definition, then it obviously cannot be a
string.
Why should the fact that some C code references the array influence
your determination of whether the array contains a string or not? Have
you bothered to look at how the code references the array? Does the
code assume the array contains a string? Does the code use any
functions that would invoke undefined behavior if the array does not
contain a string?
Your belief is does not follow from your premise.
The document calls these 8 bytes at offset 3 a "string". Whether or not
it's the C difinition or not I don't know. Evidently not.

Bill
Bill Cunningham
2014-08-19 19:19:59 UTC
Permalink
Post by Bill Cunningham
The document calls these 8 bytes at offset 3 a "string". Whether or not
it's the C difinition or not I don't know. Evidently not.
And by C definition that I understand means an added '\0' to the end. If
there's more to it than that, fill me in.

Bill
Richard Heathfield
2014-08-19 19:57:37 UTC
Permalink
Post by Bill Cunningham
Post by Bill Cunningham
The document calls these 8 bytes at offset 3 a "string". Whether or not
it's the C difinition or not I don't know. Evidently not.
And by C definition that I understand means an added '\0' to the end. If
there's more to it than that, fill me in.
There's more to it than that.

It's all about storage space.

If you decide for yourself how much storage space you need for storing
string data, C will believe you as long as it's not an obvious lie.

char s[3] = "Very long string";

is an obvious lie, and the compiler will complain.

char s[21] = "Not very long string";

is clearly not a lie. The string is twenty characters long, and you need one
for the null terminator (which C adds automatically in this case).

char s[100] = "Not very long string";

is not necessarily a lie. You might be planning to write a much larger
string into that space later, so C will allocate 100 bytes for you. It will
set the first twenty characters to the ones you specify, and fill the rest
with null characters (this is generally the case for partly initialised
arrays or structs).

char s[20] = "Not very long string";

is not an obvious lie. It might be a lie, but it isn't obvious. The problem
here is that there is no room in the array for the null terminator. But that
might be what you want! If you never treat s as a string, but only ever as
an array of 20 characters, the absence of a null terminator will not cause
you any problems BUT IT WILL CAUSE YOU PROBLEMS IF YOU TREAT s AS A STRING
so don't try to quote me as saying you don't need null terminators. Of
course you need them, to mark the end of strings.

But a definition such as:
char s[20] = "Not very long string";
is legal, and allows you to do things like:

printf("%c%c%c%c\n", s[0], s[1], s[5], s[9]);

picking out individual characters from the array.

If you just want exactly the right amount of storage for the string data you
give, though, you don't have to give a size at all:

char s[] = "Not very long string";

I recommend this course to you. If you're not planning on changing that
string, even better is:

const char s[] = "Not very long string";
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Bill Cunningham
2014-08-19 23:31:34 UTC
Permalink
Post by Richard Heathfield
There's more to it than that.
It's all about storage space.
If you decide for yourself how much storage space you need for storing
string data, C will believe you as long as it's not an obvious lie.
char s[3] = "Very long string";
is an obvious lie, and the compiler will complain.
char s[21] = "Not very long string";
is clearly not a lie. The string is twenty characters long, and you need one
for the null terminator (which C adds automatically in this case).
char s[100] = "Not very long string";
is not necessarily a lie. You might be planning to write a much larger
string into that space later, so C will allocate 100 bytes for you. It will
set the first twenty characters to the ones you specify, and fill the rest
with null characters (this is generally the case for partly initialised
arrays or structs).
char s[20] = "Not very long string";
is not an obvious lie. It might be a lie, but it isn't obvious. The problem
here is that there is no room in the array for the null terminator. But that
might be what you want! If you never treat s as a string, but only ever as
an array of 20 characters, the absence of a null terminator will not cause
you any problems BUT IT WILL CAUSE YOU PROBLEMS IF YOU TREAT s AS A STRING
so don't try to quote me as saying you don't need null terminators. Of
course you need them, to mark the end of strings.
char s[20] = "Not very long string";
printf("%c%c%c%c\n", s[0], s[1], s[5], s[9]);
picking out individual characters from the array.
If you just want exactly the right amount of storage for the string data you
char s[] = "Not very long string";
I recommend this course to you. If you're not planning on changing that
const char s[] = "Not very long string";
I myself would've coded.
char s[100]={0};
s="Not a very long string";

I don't know if it makes a difference or not. This is what seems clear to
me. 8 bytes must be used. And the "string" that is recommended just so
happens to be 8 bytes. So here is where I can't quite see what to do. maybe
this should be coded as an unsgined int? Would that be right for this FAT
area?

Bill
Melzzzzz
2014-08-19 23:33:48 UTC
Permalink
On Tue, 19 Aug 2014 19:31:34 -0400
Post by Bill Cunningham
I myself would've coded.
char s[100]={0};
s="Not a very long string";
You can't do that. Have you tried to compile it?
--
Click OK to continue...
Bill Cunningham
2014-08-19 23:37:43 UTC
Permalink
Post by Melzzzzz
On Tue, 19 Aug 2014 19:31:34 -0400
Post by Bill Cunningham
I myself would've coded.
char s[100]={0};
s="Not a very long string";
You can't do that. Have you tried to compile it?
No I should've wrote untested.

Bill
Richard Heathfield
2014-08-20 00:14:27 UTC
Permalink
Bill Cunningham wrote:

<snip>
Post by Bill Cunningham
I myself would've coded.
char s[100]={0};
s="Not a very long string";
Yes, I know you would. I wouldn't, though, because I like my programs to
work. It's a programmer thing.
Post by Bill Cunningham
I don't know if it makes a difference or not.
And this is the problem. You *need* to know that it makes a difference.
Programming is not a random activity. Successful programmers are successful
because they know what the rules are. Experimentation has its place, but it
is no substitute for a good book on C.
Post by Bill Cunningham
This is what seems clear to me.
It may seem clear, but clearly it isn't clear.
Post by Bill Cunningham
8 bytes must be used. And the "string" that is recommended just so
happens to be 8 bytes. So here is where I can't quite see what to do.
maybe this should be coded as an unsgined int? Would that be right for
this FAT area?
I think you need to abandon the FAT until you have a few more centuries of
experience. You are still at the "hello world" stage. Don't try to run
before you can stand.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Bill Cunningham
2014-08-20 00:02:04 UTC
Permalink
long text [snip]

Well here is some source code. It's coded the way I figured but the unsigned
char is an element of a struct.

typedef struct tagFAT_BOOTSECTOR32
{
// Common fields.
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <-- 8 bytes
WORD wBytsPerSec;
BYTE bSecPerClus;
WORD wRsvdSecCnt;
BYTE bNumFATs;
WORD wRootEntCnt;
WORD wTotSec16; // if zero, use dTotSec32 instead
BYTE bMedia;
WORD wFATSz16;
WORD wSecPerTrk;
WORD wNumHeads;
DWORD dHiddSec;
DWORD dTotSec32;
// Fat 32/16 only
DWORD dFATSz32;
WORD wExtFlags;
WORD wFSVer;
DWORD dRootClus;
WORD wFSInfo;
WORD wBkBootSec;
BYTE Reserved[12];
BYTE bDrvNum;
BYTE Reserved1;
BYTE bBootSig; // == 0x29 if next three fields are ok
DWORD dBS_VolID;
BYTE sVolLab[11];
BYTE sBS_FilSysType[8];

} FAT_BOOTSECTOR32;

That stupid BYTE typedef is an unsigned char too. I'm confused and not
getting anywhere.
DO you understand my plight? If I use

unsigned char BS_OEMName[]="MSWIN4.1";

I'm pretty sure I'm going to go out of the range of 8 bytes. I will test
some code though and make sure.

Bill
Richard Heathfield
2014-08-20 00:16:47 UTC
Permalink
Bill Cunningham wrote:

<snip>
Post by Bill Cunningham
DO you understand my plight?
Yes, but I don't think you do.

Your plight is that you are trying to tackle a complicated project when you
have very little understanding of the language. Dial back a little. Consider
writing simpler programs, programs that you can understand.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Bill Cunningham
2014-08-20 01:26:41 UTC
Permalink
Post by Richard Heathfield
<snip>
Post by Bill Cunningham
DO you understand my plight?
Yes, but I don't think you do.
Your plight is that you are trying to tackle a complicated project when you
have very little understanding of the language. Dial back a little. Consider
writing simpler programs, programs that you can understand.
I suppose that would be one answer. But I could also learn what I need
for what I want to do so I can do it and that would be one way to learn. I'm
not oing to grasp all the inuindos of undefined behavior, segmentation
faults and all the C situations.

The best way to learn to swim is to jump in ??

Bill
Joe Pfeiffer
2014-08-20 02:42:40 UTC
Permalink
Post by Bill Cunningham
Post by Richard Heathfield
<snip>
Post by Bill Cunningham
DO you understand my plight?
Yes, but I don't think you do.
Your plight is that you are trying to tackle a complicated project when you
have very little understanding of the language. Dial back a little. Consider
writing simpler programs, programs that you can understand.
I suppose that would be one answer. But I could also learn what I need
for what I want to do so I can do it and that would be one way to learn. I'm
not oing to grasp all the inuindos of undefined behavior, segmentation
faults and all the C situations.
The best way to learn to swim is to jump in ??
Unfortunately, it's also the best way to drown.
David Brown
2014-08-20 07:42:19 UTC
Permalink
Post by Joe Pfeiffer
Post by Bill Cunningham
Post by Richard Heathfield
<snip>
Post by Bill Cunningham
DO you understand my plight?
Yes, but I don't think you do.
Your plight is that you are trying to tackle a complicated project when you
have very little understanding of the language. Dial back a little. Consider
writing simpler programs, programs that you can understand.
I suppose that would be one answer. But I could also learn what I need
for what I want to do so I can do it and that would be one way to learn. I'm
not oing to grasp all the inuindos of undefined behavior, segmentation
faults and all the C situations.
The best way to learn to swim is to jump in ??
Unfortunately, it's also the best way to drown.
It is, in fact, a far better way to drown than to learn to swim. Bill
is attempting to learn cliff-diving, while still struggling to drink
from a cup without choking.
m***@gmail.com
2014-08-20 09:08:59 UTC
Permalink
Post by David Brown
Post by Joe Pfeiffer
Post by Bill Cunningham
The best way to learn to swim is to jump in ??
Unfortunately, it's also the best way to drown.
It is, in fact, a far better way to drown than to learn to swim. Bill
is attempting to learn cliff-diving, while still struggling to drink
from a cup without choking.
Nonsense.

Bill is masterful at getting other people to discuss the finer details of cliff-diving while he sits under a beach umbrella sipping an iced drink and enjoying the fireworks.
James Kuyper
2014-08-20 01:32:29 UTC
Permalink
Post by Richard Heathfield
<snip>
Post by Bill Cunningham
DO you understand my plight?
Yes, but I don't think you do.
Your plight is that you are trying to tackle a complicated project when you
have very little understanding of the language. Dial back a little. Consider
writing simpler programs, programs that you can understand.
Are you sure that there are any program that meet that specification?
--
James Kuyper
Bill Cunningham
2014-08-20 01:45:12 UTC
Permalink
Post by James Kuyper
Are you sure that there are any program that meet that specification?
If I listen to many...No. There never will be. Not in "centuries" :)

Bill
Richard Heathfield
2014-08-20 07:04:32 UTC
Permalink
Post by James Kuyper
Post by Richard Heathfield
<snip>
Post by Bill Cunningham
DO you understand my plight?
Yes, but I don't think you do.
Your plight is that you are trying to tackle a complicated project when
you have very little understanding of the language. Dial back a little.
Consider writing simpler programs, programs that you can understand.
Are you sure that there are any program that meet that specification?
The first comp.lang.c article from Bill Cunningham that I can find was
posted in June 2002. In it, gives the following advice:

"I don't know if Dennis Ritchie's book is still in print or not,I haven't
spoken with him for awhile. Look for "The C Programming Language" by Ritchie
and Kerninghan." [sic]

We must assume that Bill Cunningham has been studying C for at least twelve
years. Since he doesn't understand string storage, he cannot reasonably
claim to understand the "hello world" program in any depth. So the answer to
your question is probably "no". But "hello world" would make a good start.
If he can master that in the next decade or two, he should be good to go.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Barry Schwarz
2014-08-20 03:47:02 UTC
Permalink
On Tue, 19 Aug 2014 14:51:05 -0400, "Bill Cunningham"
<***@nspam.invalid> wrote:

<snip>
Post by Bill Cunningham
The document calls these 8 bytes at offset 3 a "string". Whether or not
it's the C difinition or not I don't know. Evidently not.
If you are going to use a language, don't you think it would be good
idea to have a firm grasp of the fundamentals? And when a
questionable situation arises, why are you unwilling to look at a
reference?
--
Remove del for email
Bill Cunningham
2014-08-20 04:32:53 UTC
Permalink
Post by Barry Schwarz
If you are going to use a language, don't you think it would be good
idea to have a firm grasp of the fundamentals? And when a
questionable situation arises, why are you unwilling to look at a
reference?
No no. Well that depends. Are you looking up an already understood
function? I don't need to know the ins and outs and upsidedowns of every
c89/99 function. I just need to know how to use structs and things needed
for simple filesystems.

Bill
Bill Cunningham
2014-08-18 23:52:26 UTC
Permalink
Post by Barry Schwarz
Since you did not show how you defined the array, what makes you think
there are any bits after the 64 bits that are used in the array of 8
characters?
I am just learning about what is needed in bootsectors and such. I
usually look at raw data. So when I see "MSWIN4.1" it doesn't look like
numbers to me. Maybe I'm wrong cause in binary all is numbers and this needs
to be numbers. Should my definition be,

unsigned int BS_OEMName[8]="MSWIN4.1";

Now talk about giving an error.

Bill
Osmium
2014-08-19 13:04:09 UTC
Permalink
Post by Bill Cunningham
Post by Barry Schwarz
Since you did not show how you defined the array, what makes you think
there are any bits after the 64 bits that are used in the array of 8
characters?
I am just learning about what is needed in bootsectors and such. I
usually look at raw data. So when I see "MSWIN4.1" it doesn't look like
numbers to me. Maybe I'm wrong cause in binary all is numbers and this
needs to be numbers. Should my definition be,
unsigned int BS_OEMName[8]="MSWIN4.1";
One of the first requirements for what is proper C is what your compiler
will accept. What does your compiler say when you type that ?
Post by Bill Cunningham
Now talk about giving an error.
I have no idea what that means. Is it sarcasm? A witticism? A random
thought?
Bill Cunningham
2014-08-19 23:33:39 UTC
Permalink
I seem to have trouble communicating for some reason. I speak before I
think. And it's just not here on clc, but in everyday life.

<shrug>

Bill
Richard Heathfield
2014-08-20 00:23:03 UTC
Permalink
Post by Bill Cunningham
I seem to have trouble communicating for some reason. I speak before I
think. And it's just not here on clc, but in everyday life.
In clc, at least, there is a strategy for dealing with this problem. By all
means compose a reply before you think... but don't send it. Then think it
through. Walk away, get some air, do a crossword, have some lunch, whatever.
Then come back and re-read what you've said. Does it still make sense now?
Will it make sense to someone else? Did you compile any code you included in
the article? If not, do so now. Does the result of the compilation enlighten
you? Does it change what you want to say? Does it eliminate the need to
post? If not, edit the article to reflect any changes to your understanding
that have resulted from your thinking and your compilation. Then by all
means post it.

The same applies to programs. Having written it, take a break, do something
else for a while, then come back and read the code you wrote. Do you
understand it? ALL of it? If not, go read some theory books on C. Then fix
the code.

When you are *certain* that the code is right, compile it and test it. You
will then discover that your certainty was misplaced, but that's okay as
long as you learned something from the experience.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Paul
2014-08-19 00:06:37 UTC
Permalink
Post by Barry Schwarz
On Mon, 18 Aug 2014 17:01:02 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size?
It's a string "MSWIN4.1"
After MSWIN4.1 would the rest of the bits simply be padding? There are
64 bits here to play with. But MSWIN4.1 is *specifically* requested.
Since you did not show how you defined the array, what makes you think
there are any bits after the 64 bits that are used in the array of 8
characters?
To see a working implementation, see

http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip

[fat32format.c line 488]

strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;

It sits in the middle of ...

typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;

I would have done this a different way, but then,
I'm not a C programmer.

Paul
Richard Heathfield
2014-08-19 00:12:01 UTC
Permalink
Paul wrote:

<snip>
Post by Paul
To see a working implementation, see
for certain values of "working" :-)
Post by Paul
http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip
[fat32format.c line 488]
strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
It sits in the middle of ...
typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
There's your problem right there. You're copying 9 bytes into an 8-byte
array. This is one of those times when you need memcpy.
Post by Paul
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;
I would have done this a different way, but then,
I'm not a C programmer.
I would have done this a different way, too, but then, I *am* a C
programmer.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Paul
2014-08-19 00:54:56 UTC
Permalink
Post by Richard Heathfield
<snip>
Post by Paul
To see a working implementation, see
for certain values of "working" :-)
Post by Paul
http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip
[fat32format.c line 488]
strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
It sits in the middle of ...
typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
There's your problem right there. You're copying 9 bytes into an 8-byte
array. This is one of those times when you need memcpy.
Post by Paul
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;
I would have done this a different way, but then,
I'm not a C programmer.
I would have done this a different way, too, but then, I *am* a C
programmer.
Well, I wasn't sure it would copy nine bytes or not.
I figured the placement of the

pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;

was "strategic" :-) Initializing right after the damage
is done, or something.

The code is "working" only in that it demonstrates
interpretation of the various fields in a FAT partition.
And it does format over-sized partitions here just fine.
Windows eats them OK. We need this silly utility, because
WinXP won't format FAT32 partitions larger than 32GB.
Whereas, for some hero experiments, you need it to work
all the way up to 2.2TB (just to see if Windows can
actually handle a file allocation table which is 1GB in size).

Paul
Bill Cunningham
2014-08-19 03:09:01 UTC
Permalink
Post by Paul
Post by Richard Heathfield
<snip>
Post by Paul
To see a working implementation, see
for certain values of "working" :-)
Post by Paul
http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip
[fat32format.c line 488]
strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
It sits in the middle of ...
typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
There's your problem right there. You're copying 9 bytes into an 8-byte
array. This is one of those times when you need memcpy.
Post by Paul
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;
I would have done this a different way, but then,
I'm not a C programmer.
I would have done this a different way, too, but then, I *am* a C
programmer.
Well, I wasn't sure it would copy nine bytes or not.
I figured the placement of the
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
was "strategic" :-) Initializing right after the damage
is done, or something.
The code is "working" only in that it demonstrates
interpretation of the various fields in a FAT partition.
And it does format over-sized partitions here just fine.
Windows eats them OK. We need this silly utility, because
WinXP won't format FAT32 partitions larger than 32GB.
Whereas, for some hero experiments, you need it to work
all the way up to 2.2TB (just to see if Windows can
actually handle a file allocation table which is 1GB in size).
I hate those MS typedefs. I don't know what they really are.

Bill
Bill Cunningham
2014-08-19 20:39:40 UTC
Permalink
Post by Paul
The code is "working" only in that it demonstrates
interpretation of the various fields in a FAT partition.
And it does format over-sized partitions here just fine.
Windows eats them OK. We need this silly utility, because
WinXP won't format FAT32 partitions larger than 32GB.
Actually if you are making a clean install with an older XP disk, if you
set the partition size to 120-140 GB XP will give an option to format in
fat32. Then you can expand your paritition. And XP handles it.
Post by Paul
Whereas, for some hero experiments, you need it to work
all the way up to 2.2TB (just to see if Windows can
actually handle a file allocation table which is 1GB in size).
Mine does all the time.
Barry Schwarz
2014-08-19 03:43:40 UTC
Permalink
Post by Paul
Post by Richard Heathfield
<snip>
Post by Paul
To see a working implementation, see
for certain values of "working" :-)
Post by Paul
http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip
[fat32format.c line 488]
strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
It sits in the middle of ...
typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
There's your problem right there. You're copying 9 bytes into an 8-byte
array. This is one of those times when you need memcpy.
Post by Paul
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;
I would have done this a different way, but then,
I'm not a C programmer.
I would have done this a different way, too, but then, I *am* a C
programmer.
Well, I wasn't sure it would copy nine bytes or not.
How could it not copy 9 bytes? You are using strcpy and the source
string occupies 9 bytes. strncpy and memcpy both provide a means of
ensuring you don't overrun the target.
Post by Paul
I figured the placement of the
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
was "strategic" :-) Initializing right after the damage
is done, or something.
You cannot correct undefined behavior after the fact. As you say, the
damage is already done.
Post by Paul
The code is "working" only in that it demonstrates
The code is "working" only in that the generated instruction do the
expected. What would happen if the optimizer found a reason to
implement the instructions in a different order?
Post by Paul
interpretation of the various fields in a FAT partition.
And it does format over-sized partitions here just fine.
Windows eats them OK. We need this silly utility, because
WinXP won't format FAT32 partitions larger than 32GB.
Whereas, for some hero experiments, you need it to work
all the way up to 2.2TB (just to see if Windows can
actually handle a file allocation table which is 1GB in size).
--
Remove del for email
Bill Cunningham
2014-08-20 05:00:13 UTC
Permalink
Post by Paul
Post by Richard Heathfield
<snip>
Post by Paul
To see a working implementation, see
for certain values of "working" :-)
Post by Paul
http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip
[fat32format.c line 488]
strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
It sits in the middle of ...
typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
There's your problem right there. You're copying 9 bytes into an 8-byte
array. This is one of those times when you need memcpy.
Post by Paul
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;
I would have done this a different way, but then,
I'm not a C programmer.
I would have done this a different way, too, but then, I *am* a C
programmer.
Well, I wasn't sure it would copy nine bytes or not.
I figured the placement of the
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
was "strategic" :-) Initializing right after the damage
is done, or something.
[snip] extra

Well does it copy 9 bytes by the look of it. I can't expect you to code it
but does it look like it might fail?

Bill
Paul
2014-08-20 07:00:11 UTC
Permalink
Post by Bill Cunningham
Post by Paul
Post by Richard Heathfield
<snip>
Post by Paul
To see a working implementation, see
for certain values of "working" :-)
Post by Paul
http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip
[fat32format.c line 488]
strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
It sits in the middle of ...
typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
There's your problem right there. You're copying 9 bytes into an 8-byte
array. This is one of those times when you need memcpy.
Post by Paul
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;
I would have done this a different way, but then,
I'm not a C programmer.
I would have done this a different way, too, but then, I *am* a C
programmer.
Well, I wasn't sure it would copy nine bytes or not.
I figured the placement of the
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
was "strategic" :-) Initializing right after the damage
is done, or something.
[snip] extra
Well does it copy 9 bytes by the look of it. I can't expect you to code it
but does it look like it might fail?
Bill
The problem involves a large array of bytes (a "sector").
Items stored in there, are just byte values.

But for fun, the specification defines an 8 byte array of char,
with a magic group of characters. On either side of the grouping,
are other important pieces of data.

Due to the proximity of other material in the array, the options
are:

1) Copy the eight items M,S,W,I,N,4,., and 1,
one at a time. The item as described in the specification
is not a string, but just eight adjacent bytes.

2) To strcpy "MSWIN4.1" operation would copy nine bytes into
an eight byte hole. That's an overflowing of the storage space
and wrong. Since the author at Ridgecrop immediately overwrites
the next two bytes in the next line of code, maybe he didn't
care about the bad programming practice, and did those purely
so you could see the string "MSWIN4.1" in print. It is also possible
the Ridgecrop author copied this from somewhere else.

3) Another way to do it is with strncpy, where you can specify a
length of 8, chopping off the null on the end of the constant,
and not damaging the adjacent location.

That's my interpretation of what is going on. I would prefer (1)
above, as by doing so, I would be pointing out to the reader of
my code, that there is no room to store a trailing null of a traditional
C "string" constant, in the hole provided.

Solution (3) preserves the Ridgecrop author's attempt to make it
look like a string, but without damaging anything when the
strncpy runs.

http://linux.die.net/man/3/strncpy

"Warning: If there is no null byte among the first n bytes of src,
the string placed in dest will not be null-terminated."

And that is *exactly* what we want in this case, given that this
constant ("MSWIN4.1") is nine bytes long, and in actual fact we
only want the first n=8 to be copied. The n=8 would be the last
parameter in the strncpy call.

I couldn't believe my eyes, and wanted someone else to point
out the very bad practice.

Paul
Richard Heathfield
2014-08-20 07:12:17 UTC
Permalink
Post by Bill Cunningham
Post by Paul
Post by Richard Heathfield
<snip>
Post by Paul
To see a working implementation, see
for certain values of "working" :-)
Post by Paul
http://www.ridgecrop.demon.co.uk/download/fat32formatsrc.zip
[fat32format.c line 488]
strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
It sits in the middle of ...
typedef struct tagFAT_BOOTSECTOR32
{
BYTE sJmpBoot[3];
BYTE sOEMName[8]; <---
There's your problem right there. You're copying 9 bytes into an 8-byte
array. This is one of those times when you need memcpy.
Post by Paul
WORD wBytsPerSec; <---
...
} FAT_BOOTSECTOR32;
I would have done this a different way, but then,
I'm not a C programmer.
I would have done this a different way, too, but then, I *am* a C
programmer.
Well, I wasn't sure it would copy nine bytes or not.
I figured the placement of the
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
was "strategic" :-) Initializing right after the damage
is done, or something.
[snip] extra
Well does it copy 9 bytes by the look of it. I can't expect you to code it
but does it look like it might fail?
A gallon is eight pints. You have a gallon bucket. You pour nine pints of
water into it. You think something might go wrong with that, that you might
spill some? Hmmm?

9 into 8 won't go. The extra character won't fit in the eight bytes. So it
will have to go somewhere else. Wherever else you put it, it's going to be
overwriting a value that it shouldn't be overwriting. Writing data where it
doesn't belong is a BAD THING. NO BISCUIT.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Barry Schwarz
2014-08-18 21:42:47 UTC
Permalink
On Mon, 18 Aug 2014 16:57:04 -0400, "Bill Cunningham"
<***@nspam.invalid> wrote:

<snip>
Post by Bill Cunningham
That's exactly what I thought. My first mistake was by habit using the
%s instead of %c. But you know when I tried %c on both of these there was
some weird garbage that printed out.
Since you are attempting to access a non-existent object (the ninth
element of an 8 element array), be thankful this particular example of
undefined behavior did not damage your system or provide an output
that would have led you to believe your code was working.
Post by Bill Cunningham
Anyway the MBR and docs I'm looking at declare a specific offset and
room for 8 bytes.
http://home.teleport.com/~brainy/fatgen102.pdf
While this web site does contain the statement that data types are
unsigned, the context of the statement makes it clear it is referring
to numeric values only. There is no need to declare your array as
unsigned character.
Post by Bill Cunningham
Page 8 offset 3 8 bytes. Now wouldn't the type be a char of some size? It's
a string "MSWIN4.1"
As others have repeatedly told you, it is not a string. Your
insistence on treating it as such belies any claims you make to
understanding what is wrong with your code or how you fixed it.
--
Remove del for email
Ben Bacarisse
2014-08-18 21:28:47 UTC
Permalink
<snip>
Post by Richard Heathfield
Post by Bill Cunningham
int main()
{
unsigned char BS_OEMName[8] = "MSWIN4.1";
<snip>
Post by Richard Heathfield
Post by Bill Cunningham
char BS_OEMName2[8] = "MSWIN4.1";
Same here.
Post by Bill Cunningham
printf("%s\n%s\n", BS_OEMName[8], BS_OEMName2[8]);
<snip>
Post by Richard Heathfield
The right way to print a single character is with %c. If you want to print
strings, %s is fine, but you need to pass to printf a pointer to the first
character in the string. Unfortunately, you don't have strings, since
neither of your arrays is null-terminated.
If you want strings, specify enough storage to allow for a null terminator,
unsigned char BS_OEMName[] = "MSWIN4.1";
char BS_OEMName2[] = "MSWIN4.1";
It's probably worth pointing out that %s can be used (modified) for
printing non-strings such as those in the original code:

char BS_OEMName[8] = "MSWIN4.1"
printf("%.8s\n", BS_OEMName);

or, better,

printf("%.*s\n", (int)sizeof BS_OEMName, BS_OEMName);

Very occasionally, you are stuck with a structure you can't change that
stores values in this un-terminated form. The "%.*" form is quote
useful for other things, too.
--
Ben.
Ike Naar
2014-08-18 20:45:20 UTC
Permalink
Post by Bill Cunningham
Post by Barry Schwarz
Post by Bill Cunningham
Post by Barry Schwarz
Show your code.
I think I figure out my bug. In printing out one value being name[8].
The last charater I used in the printf format specifier %s instead if %c
by habit. Would that do it?
No.
Show your code.
#include <stdio.h>
int main()
int main(void)
Post by Bill Cunningham
{
unsigned char BS_OEMName[8] = "MSWIN4.1";
char BS_OEMName2[8] = "MSWIN4.1";
printf("%s\n%s\n", BS_OEMName[8], BS_OEMName2[8]);
There's no such thing as BS_OEMName[8] or BS_OEMName2[8].
Post by Bill Cunningham
return 0;
}
Bill Cunningham
2014-08-18 20:46:09 UTC
Permalink
Post by Bill Cunningham
#include <stdio.h>
int main()
{
unsigned char BS_OEMName[8] = "MSWIN4.1";
char BS_OEMName2[8] = "MSWIN4.1";
printf("%s\n%s\n", BS_OEMName[8], BS_OEMName2[8]);
return 0;
}
That just goes to show you that a char and an unsigned char are NOT the
same thing. I'm not sure of the difference right off the top of my head.
I've never used unsigneds. I'd have to lok it up. Ranges in size maybe.
That's the way ints are.

Bill
Barry Schwarz
2014-08-18 21:59:01 UTC
Permalink
On Mon, 18 Aug 2014 16:46:09 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Bill Cunningham
#include <stdio.h>
int main()
{
unsigned char BS_OEMName[8] = "MSWIN4.1";
char BS_OEMName2[8] = "MSWIN4.1";
printf("%s\n%s\n", BS_OEMName[8], BS_OEMName2[8]);
return 0;
}
That just goes to show you that a char and an unsigned char are NOT the
same thing. I'm not sure of the difference right off the top of my head.
I've never used unsigneds. I'd have to lok it up. Ranges in size maybe.
That's the way ints are.
It shows no such thing. If anything, it shows that you don't
understand undefined behavior. If you coded it correctly to remove
the undefined behavior, it MIGHT show that char and unsigned char are
not the same thing. But the two have always been distinct types, even
if your compiler chooses to make char unsigned. char, unsigned char,
and signed char are always distinct types, even though two of the
three will always share most of there characteristics.

All three char types are required to have sizeof 1. So ranges in size
is not one of the possible differences.

What does the "way ints are" have to do with any differences between
char and unsigned char? Why did you interject a superfluous and
meaningless comment about a type that is not at all part of the
discussion?
--
Remove del for email
Bill Cunningham
2014-08-20 01:47:43 UTC
Permalink
Post by Barry Schwarz
What does the "way ints are" have to do with any differences between
char and unsigned char? Why did you interject a superfluous and
meaningless comment about a type that is not at all part of the
discussion?
Ok Barry never mind. Maybe we should just let the whole thing drop.

Bill
Malcolm McLean
2014-08-18 22:14:33 UTC
Permalink
Post by Bill Cunningham
That just goes to show you that a char and an unsigned char are NOT the
same thing. I'm not sure of the difference right off the top of my head.
I've never used unsigneds. I'd have to lok it up. Ranges in size maybe.
That's the way ints are.
There's little reason to ever use unsigneds. Some programmers use
unsigned to document that a value naturally can't be negative, like
the number of employees on a payroll. This is almost always a bad
idea.
The exception is unsigned char. It's a funny one. Really it means
"byte". It's used for storing arbitrary bits, treating them as
bit patterns rather than higher-level objects.
Richard Heathfield
2014-08-18 22:40:52 UTC
Permalink
Malcolm McLean wrote:

<snip>
Post by Malcolm McLean
There's little reason to ever use unsigneds.
Counts, sizes, hashes, to name but three common reasons for using unsigned
integer types.

<snip>
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
James Kuyper
2014-08-18 22:49:51 UTC
Permalink
Post by Richard Heathfield
<snip>
Post by Malcolm McLean
There's little reason to ever use unsigneds.
Counts, sizes, hashes, to name but three common reasons for using unsigned
integer types.
Bitwise operations such as unary ~, and binary <<, >>, &, ^, and | are
another good reason.
David Brown
2014-08-19 07:07:49 UTC
Permalink
Post by James Kuyper
Post by Richard Heathfield
<snip>
Post by Malcolm McLean
There's little reason to ever use unsigneds.
Counts, sizes, hashes, to name but three common reasons for using unsigned
integer types.
Bitwise operations such as unary ~, and binary <<, >>, &, ^, and | are
another good reason.
On very small processors, speed is another reason - there are a number
of older small cpu designs that cannot easily do signed comparisons, and
if the cpu does not have hardware for multiplication or division then
using unsigned integers for these operations is much faster.

As a general point, in small embedded systems, it is extremely common to
use unsigned data.


I think it is also common to use unsigned chars for UTF-8 character
data, or indeed any 8-bit character data beyond ASCII (and similarly
uint16_t for UTF-16 and uint32_t for UTF-32).
Malcolm McLean
2014-08-19 08:18:31 UTC
Permalink
Post by David Brown
On very small processors, speed is another reason - there are a number
of older small cpu designs that cannot easily do signed comparisons, and
if the cpu does not have hardware for multiplication or division then
using unsigned integers for these operations is much faster.
Effectively you're using C as a slightly abstracted assembler there.
The snag with unsigned is that N - 1 yields a large value if N = 0.
That creates bugs which often slip through, because often N can't
be zero, until something changes higher up, and it can.
Post by David Brown
I think it is also common to use unsigned chars for UTF-8 character
data, or indeed any 8-bit character data beyond ASCII (and similarly
uint16_t for UTF-16 and uint32_t for UTF-32).
No, bad idea.

Pass UTF-8 about as plain char strings. At the last moment, provide
a char * to int, and int to char buffer conversion. You want a
signed int so you can use -1 to flag an error.
Then it's all transparent to C functions, which is the idea.
David Brown
2014-08-19 09:20:43 UTC
Permalink
Post by Malcolm McLean
Post by David Brown
On very small processors, speed is another reason - there are a number
of older small cpu designs that cannot easily do signed comparisons, and
if the cpu does not have hardware for multiplication or division then
using unsigned integers for these operations is much faster.
Effectively you're using C as a slightly abstracted assembler there.
No, I am using C as C. I have programmed for decades in both C and
assembler, and I know the difference. I am programming in C with a
knowledge of the underlying machine architecture - but that is
completely different from pretending C is a sort of "high level assembler".
Post by Malcolm McLean
The snag with unsigned is that N - 1 yields a large value if N = 0.
That creates bugs which often slip through, because often N can't
be zero, until something changes higher up, and it can.
That "snag" is an artificial argument. If I write incorrect code, there
will be a bug - using signed or unsigned integers will not affect that.
How do I know I never try to write "N - 1" when N is an unsigned
integer with value 0? Because I write my code carefully, with careful
checks and tests. And if you think it helps to change N to be a signed
integer, so that an incorrect "N - 1" is a small negative value rather
than a large positive one, you are delusional - dangerously so.
Post by Malcolm McLean
Post by David Brown
I think it is also common to use unsigned chars for UTF-8 character
data, or indeed any 8-bit character data beyond ASCII (and similarly
uint16_t for UTF-16 and uint32_t for UTF-32).
No, bad idea.
Pass UTF-8 about as plain char strings. At the last moment, provide
a char * to int, and int to char buffer conversion. You want a
signed int so you can use -1 to flag an error.
That makes no sense whatsoever.

For the most part, it won't make a difference if data is passed around
as "char", "signed char" or "unsigned char" - the underlying cpu
representation is going to be the same. It will only make a difference
when you want to interpret the data, and that means bit manipulation
(bit testing, masking, shifting, etc.), which means unsigned operations.
Thus unsigned chars are the natural choice for UTF-8, but for
user-level code that doesn't interpret the characters, plain char will
work fine too.

At no point do you convert a "char*" - a pointer - into an "int". Such
conversions in normal code are either an indication of bad function
interface, or directly wrong (such as on a target with 64-bit pointers
and 32-bit int). (There are occasions in very low-level code when
conversions between pointers and integer types are useful, but not in
"normal" code.)

I don't even know what "int to char buffer conversion" is supposed to mean.


Error handling is, of course, important in cases when an error can occur
- but you don't do it by trying to return a "pointer" of "-1".
Post by Malcolm McLean
Then it's all transparent to C functions, which is the idea.
Malcolm McLean
2014-08-19 17:37:42 UTC
Permalink
Post by David Brown
At no point do you convert a "char*" - a pointer - into an "int".
I don't even know what "int to char buffer conversion" is supposed to mean.
It's very simple.
You need two functions.

int utf8toch(char *str, int *skip);

and another one

int chtoutf8(int ch, char *out);

You should return an negative value on error (not passed a valid UFT-8#
string). So the return value need to be int rather than unsigned int.
David Brown
2014-08-19 22:54:13 UTC
Permalink
Post by Malcolm McLean
Post by David Brown
At no point do you convert a "char*" - a pointer - into an "int".
I don't even know what "int to char buffer conversion" is supposed to mean.
It's very simple.
You need two functions.
int utf8toch(char *str, int *skip);
and another one
int chtoutf8(int ch, char *out);
You should return an negative value on error (not passed a valid UFT-8#
string). So the return value need to be int rather than unsigned int.
If you have a function that takes an input, generates an output, and may
fail, then the traditional C method is that the "output" parameter is a
pointer, and the return value is a signed int return code - negative
values for errors, 0 for success, and occasionally positive for other
successful values. The negative error codes might be mixed with
non-negative successful return values for things like lengths, file
handles, etc., I would not want to mix it them with character data. I
am not clear on what your functions here are trying to return - at a
guess, it might be utf-32 characters. In that case, the code could
work, since valid utf-32 characters go up to 0x7fffffff, but I would
feel very uncomfortable with the code like that. And I certainly
wouldn't use a plain "int" - I would use int32_t (or more likely, a
typedef).
Malcolm McLean
2014-08-19 17:47:00 UTC
Permalink
Post by David Brown
That "snag" is an artificial argument. If I write incorrect code, there
will be a bug - using signed or unsigned integers will not affect that.
How do I know I never try to write "N - 1" when N is an unsigned
integer with value 0? Because I write my code carefully, with careful
checks and tests. And if you think it helps to change N to be a signed
integer, so that an incorrect "N - 1" is a small negative value rather
than a large positive one, you are delusional - dangerously so.
Often you need N-1. For example we've a list of reals which represent
time intervals, in ascending order, and we want to do an operation
on all the midpoints of the time intervals.
Now N-1 is negative if N = 0. That's not an error, usually at least.

the code

for(i=0;i<N-1;i++)
{
dointerval( (t[i] + t[i+1])/2.0 );
}

is fine. Until you go to unsigned integers. Then you need to be
careful. You need to be especially careful because the N = 0 corner
case is probably one which won't be generated on a normal run,
so the bug is likely to slip through until a late and expensive
stage.
unsigned is usually a sign of bad programming. There are a few
exceptions, e.g. the intermediate accumulator for a hash,
unsigned bytes for things like RGB colour values, and maybe
micro-optimisation for some processors which aren't intended
for general-purpose use and don't have fast signed arithmetic
(which is effectively using C as a high-level assembler).
Richard Heathfield
2014-08-19 18:26:09 UTC
Permalink
Malcolm McLean wrote:

<snip>
Post by James Kuyper
the code
for(i=0;i<N-1;i++)
{
dointerval( (t[i] + t[i+1])/2.0 );
}
is fine. Until you go to unsigned integers. Then you need to be
careful. You need to be especially careful because the N = 0 corner
case is probably one which won't be generated on a normal run,
so the bug is likely to slip through until a late and expensive
stage.
It's highly UNlikely that this will "slip through", because corner cases are
among the most important parts of the test plan.
Post by James Kuyper
unsigned is usually a sign of bad programming.
Malcolm, I realise that you don't like unsigned integers, but you are
massively overstating your case here. Unsigned integers are fundamental
tools which, used correctly, can be much more robust than signed integers in
a number of circumstances. You have already been given several examples, the
most obvious of which are counts and sizes.

Use the right tool for the job. Don't artificially limit your tools by
throwing out good tools just because their handle isn't your favourite
colour.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
David Brown
2014-08-19 23:01:05 UTC
Permalink
Post by Malcolm McLean
Post by David Brown
That "snag" is an artificial argument. If I write incorrect code, there
will be a bug - using signed or unsigned integers will not affect that.
How do I know I never try to write "N - 1" when N is an unsigned
integer with value 0? Because I write my code carefully, with careful
checks and tests. And if you think it helps to change N to be a signed
integer, so that an incorrect "N - 1" is a small negative value rather
than a large positive one, you are delusional - dangerously so.
Often you need N-1. For example we've a list of reals which represent
time intervals, in ascending order, and we want to do an operation
on all the midpoints of the time intervals.
Now N-1 is negative if N = 0. That's not an error, usually at least.
the code
for(i=0;i<N-1;i++)
{
dointerval( (t[i] + t[i+1])/2.0 );
}
is fine. Until you go to unsigned integers. Then you need to be
careful. You need to be especially careful because the N = 0 corner
case is probably one which won't be generated on a normal run,
so the bug is likely to slip through until a late and expensive
stage.
unsigned is usually a sign of bad programming. There are a few
exceptions, e.g. the intermediate accumulator for a hash,
unsigned bytes for things like RGB colour values, and maybe
micro-optimisation for some processors which aren't intended
for general-purpose use and don't have fast signed arithmetic
(which is effectively using C as a high-level assembler).
Again, please drop the cliché about C as a high-level assembler.

Of course there may be occasions when a test such as "i < (N - 1)" is
used. And it is possible that making N unsigned rather than signed
would be convenient - but it is more likely that explicit tests for
valid ranges and corner cases will be clearer and more appropriate. And
certainly if your code quality and testing is so poor that such corner
cases slip by as bugs just because N is unsigned, then you are going to
have far more problems to worry about.

Feel free to drop half the useful arithmetic types in C for your own
coding, but please do not rant to those of us who make good use of
different types for different purposes, and find them useful for a type
of programming with which you are apparently unfamiliar.
Kaz Kylheku
2014-08-19 18:33:41 UTC
Permalink
Post by David Brown
Post by Malcolm McLean
The snag with unsigned is that N - 1 yields a large value if N = 0.
That creates bugs which often slip through, because often N can't
be zero, until something changes higher up, and it can.
That "snag" is an artificial argument. If I write incorrect code, there
will be a bug - using signed or unsigned integers will not affect that.
How do I know I never try to write "N - 1" when N is an unsigned
integer with value 0? Because I write my code carefully, with careful
checks and tests. And if you think it helps to change N to be a signed
integer, so that an incorrect "N - 1" is a small negative value rather
than a large positive one, you are delusional - dangerously so.
It helps because you can have

assert (N - 1 >= 0)

to trap this situation. If N is unsigned, the condition is never false.

The assertion is possible because the signed type behaves more similarly to
a mathematical integer than does an unsigned type.

Ideally, we would program using integers that behave like mathematical integers
in every regard.
Richard Heathfield
2014-08-19 18:52:44 UTC
Permalink
Kaz Kylheku wrote:

<snip>
Post by Kaz Kylheku
Ideally, we would program using integers that behave like mathematical
integers in every regard.
Mathematicians distinguish between the integers, the negative integers, the
positive integers, the non-negative integers, and the non-positive integers.
Wolfram defines these as Z, Z-, Z-+, Z-*, and {0}UZ- respectively.

Unsigned integers are a good match for Z-*.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Malcolm McLean
2014-08-19 19:21:16 UTC
Permalink
Post by Kaz Kylheku
Ideally, we would program using integers that behave like mathematical
integers in every regard.
Exactly.
The logic goes that some values are inherently non-negative, so
unsigned documents that. There's also the irritating, but not
practically very important, case that if a memory object takes up
more than half the address space, then often a signed integer won't
index it whilst an unsigned integer will.

But intermediate values can often go negative. It's very common to
want the previous element in an array. Obviously, when i == 0
you need some special code. But if j is -1, this can be a generic
wrap or clamp j = (j + N) % N, or j = clamp(j, 0, N-1). If j goes
to 0xFFFFFFFF then it's much tricker to get right. It is of
course possible to code correctly using unsigned integers, it's
a case of clarity and likeliness of avoiding bugs.
David Brown
2014-08-19 23:07:03 UTC
Permalink
Post by Malcolm McLean
Post by Kaz Kylheku
Ideally, we would program using integers that behave like mathematical
integers in every regard.
Exactly.
The logic goes that some values are inherently non-negative, so
unsigned documents that. There's also the irritating, but not
practically very important, case that if a memory object takes up
more than half the address space, then often a signed integer won't
index it whilst an unsigned integer will.
Again, you are showing your blinkered view of programming. Perhaps you
are unaware that a significant majority of processors in current use
have 16-bit ints, and for which making use of the extra bit available in
unsigned types (for counting, for addresses, or other purposes) is
highly relevant.
Post by Malcolm McLean
But intermediate values can often go negative. It's very common to
want the previous element in an array. Obviously, when i == 0
you need some special code. But if j is -1, this can be a generic
wrap or clamp j = (j + N) % N, or j = clamp(j, 0, N-1). If j goes
to 0xFFFFFFFF then it's much tricker to get right. It is of
course possible to code correctly using unsigned integers, it's
a case of clarity and likeliness of avoiding bugs.
It is perfectly possible to write such code correctly using unsigned
types. Usually it is far easier to do so in a clear and correct manner
using unsigned types, because unsigned overflow is well defined in C -
unlike signed overflow.
David Brown
2014-08-19 23:02:22 UTC
Permalink
Post by Kaz Kylheku
Post by David Brown
Post by Malcolm McLean
The snag with unsigned is that N - 1 yields a large value if N = 0.
That creates bugs which often slip through, because often N can't
be zero, until something changes higher up, and it can.
That "snag" is an artificial argument. If I write incorrect code, there
will be a bug - using signed or unsigned integers will not affect that.
How do I know I never try to write "N - 1" when N is an unsigned
integer with value 0? Because I write my code carefully, with careful
checks and tests. And if you think it helps to change N to be a signed
integer, so that an incorrect "N - 1" is a small negative value rather
than a large positive one, you are delusional - dangerously so.
It helps because you can have
assert (N - 1 >= 0)
to trap this situation. If N is unsigned, the condition is never false.
The assertion is possible because the signed type behaves more similarly to
a mathematical integer than does an unsigned type.
Ideally, we would program using integers that behave like mathematical integers
in every regard.
assert(N >= 1);

Case closed.
Kaz Kylheku
2014-08-19 23:18:37 UTC
Permalink
Post by David Brown
Post by Kaz Kylheku
Post by David Brown
Post by Malcolm McLean
The snag with unsigned is that N - 1 yields a large value if N = 0.
That creates bugs which often slip through, because often N can't
be zero, until something changes higher up, and it can.
That "snag" is an artificial argument. If I write incorrect code, there
will be a bug - using signed or unsigned integers will not affect that.
How do I know I never try to write "N - 1" when N is an unsigned
integer with value 0? Because I write my code carefully, with careful
checks and tests. And if you think it helps to change N to be a signed
integer, so that an incorrect "N - 1" is a small negative value rather
than a large positive one, you are delusional - dangerously so.
It helps because you can have
assert (N - 1 >= 0)
to trap this situation. If N is unsigned, the condition is never false.
The assertion is possible because the signed type behaves more similarly to
a mathematical integer than does an unsigned type.
Ideally, we would program using integers that behave like mathematical integers
in every regard.
assert(N >= 1);
Case closed.
The above algebraic transformation only applies to the situation when N == 0
is not an allowed value, and it only catches an off by one error which
produces the value, not an off by two or more.

If N is signed, assert (N - 1 >= 0) will catch situations when N has mistakenly
dropped to, for instance, -42.

If N is unsigned, these situations translate to some large value which
passes either version of the assertion, whether (N - 1 >= 0) or (N >= 1).

We can also make this kind of algebraic transformation involving an inequality
with more confidence over the signed types.

If N is unsigned, (N >= 1) has quite a different behavior from assert (N - 1 >=
0). One is false for zero, the other never false. This is a consequence of the
unsigned type poorly corresponding to algebraic integers.

If N is signed, the only difference has to do with the N - 1 possibly
underflowing (another a manifestation of the discrepancy between machine
numbers and integers). In the absence of that overflow, the semantics is
preserved.
David Brown
2014-08-20 00:33:04 UTC
Permalink
Post by Kaz Kylheku
Post by David Brown
Post by Kaz Kylheku
Post by David Brown
Post by Malcolm McLean
The snag with unsigned is that N - 1 yields a large value if N = 0.
That creates bugs which often slip through, because often N can't
be zero, until something changes higher up, and it can.
That "snag" is an artificial argument. If I write incorrect code, there
will be a bug - using signed or unsigned integers will not affect that.
How do I know I never try to write "N - 1" when N is an unsigned
integer with value 0? Because I write my code carefully, with careful
checks and tests. And if you think it helps to change N to be a signed
integer, so that an incorrect "N - 1" is a small negative value rather
than a large positive one, you are delusional - dangerously so.
It helps because you can have
assert (N - 1 >= 0)
to trap this situation. If N is unsigned, the condition is never false.
The assertion is possible because the signed type behaves more similarly to
a mathematical integer than does an unsigned type.
Ideally, we would program using integers that behave like mathematical integers
in every regard.
assert(N >= 1);
Case closed.
The above algebraic transformation only applies to the situation when N == 0
is not an allowed value, and it only catches an off by one error which
produces the value, not an off by two or more.
If N is signed, assert (N - 1 >= 0) will catch situations when N has mistakenly
dropped to, for instance, -42.
You are talking about unhelpful checking of unrealistic issues. If your
program involves a value N that is not supposed to go below zero, then
catching a value of -42 at this stage is closing the gate after the
horse has bolted.

There is no need for an assertion like this - like most assertions, they
are a sign that you haven't written your code properly (or at best, you
are not sure that you have written your code properly and have it there
to help debugging). The way you avoid having problems with negative N
is by not giving N a negative value. Making N unsigned will make that
clear in the program - for the benefit of programmers and the compiler -
and help the compiler and/or static error checkers and/or run-time
checkers spot some mistakes that violate your requirements for N.
Post by Kaz Kylheku
If N is unsigned, these situations translate to some large value which
passes either version of the assertion, whether (N - 1 >= 0) or (N >= 1).
We can also make this kind of algebraic transformation involving an inequality
with more confidence over the signed types.
If N is unsigned, (N >= 1) has quite a different behavior from assert (N - 1 >=
0). One is false for zero, the other never false. This is a consequence of the
unsigned type poorly corresponding to algebraic integers.
unsigned types work fine as long as you understand what you are doing,
and understand basic arithmetic. And if you don't understand, you
should be doing something else.
Post by Kaz Kylheku
If N is signed, the only difference has to do with the N - 1 possibly
underflowing (another a manifestation of the discrepancy between machine
numbers and integers). In the absence of that overflow, the semantics is
preserved.
unsigned and signed integers have different pros and cons, and different
optimal use-cases. Learn the difference - don't try to imagine that
signed integers are somehow superior, or "closer to mathematical
integers", because they are not.
Richard Heathfield
2014-08-20 06:49:25 UTC
Permalink
David Brown wrote:

<snip>
Post by David Brown
There is no need for an assertion like this - like most assertions, they
are a sign that you haven't written your code properly (or at best, you
are not sure that you have written your code properly and have it there
to help debugging).
That's not "at best". "At best" is when you *are* sure you've written your
code properly and you're only putting the assertion in there because your
house rules tell you to, and you know it's a complete waste of time as it
will never, ever, fire.

That way, when the assertion does fire, you learn something, which is always
nice.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
David Brown
2014-08-20 07:55:08 UTC
Permalink
Post by Richard Heathfield
<snip>
Post by David Brown
There is no need for an assertion like this - like most assertions, they
are a sign that you haven't written your code properly (or at best, you
are not sure that you have written your code properly and have it there
to help debugging).
That's not "at best". "At best" is when you *are* sure you've written your
code properly and you're only putting the assertion in there because your
house rules tell you to, and you know it's a complete waste of time as it
will never, ever, fire.
That way, when the assertion does fire, you learn something, which is always
nice.
"Defensive programming" certainly has its place - and over-confidence is
a bad plan.

My aversion to run-time asserts (static asserts are very different, and
very useful) comes partly from the type of program I work with, and
partly from the abuse some people make of asserts (as crutches instead
of making sure their code is correct in the first place, or instead of
appropriate run-time checks). For desktop programs, it can be useful to
stop with an error during testing and debugging - it may even be
acceptable to leave in the assertions after release. But for embedded
systems, stopping the program with an error message is seldom a good
idea. You need proper run-time checks, with carefully considered
handling of the error condition - not a generic "panic" reaction.

And putting in code that cannot run "just in case" means added
complexity, bigger code (which is often relevant for embedded systems),
and code paths that can never be tested. That is not something I like
to have in my programs.
Barry Schwarz
2014-08-19 04:36:11 UTC
Permalink
On Mon, 18 Aug 2014 15:14:33 -0700 (PDT), Malcolm McLean
Post by Malcolm McLean
Post by Bill Cunningham
That just goes to show you that a char and an unsigned char are NOT the
same thing. I'm not sure of the difference right off the top of my head.
I've never used unsigneds. I'd have to lok it up. Ranges in size maybe.
That's the way ints are.
There's little reason to ever use unsigneds. Some programmers use
unsigned to document that a value naturally can't be negative, like
the number of employees on a payroll. This is almost always a bad
idea.
The exception is unsigned char. It's a funny one. Really it means
"byte". It's used for storing arbitrary bits, treating them as
bit patterns rather than higher-level objects.
There are machines (e.g., IBM mainframes using EBCDIC) where normal
characters need to be unsigned (among other reasons, so the functions
in ctype.h can work).
--
Remove del for email
David Brown
2014-08-19 23:07:52 UTC
Permalink
Post by Barry Schwarz
On Mon, 18 Aug 2014 15:14:33 -0700 (PDT), Malcolm McLean
Post by Malcolm McLean
Post by Bill Cunningham
That just goes to show you that a char and an unsigned char are NOT the
same thing. I'm not sure of the difference right off the top of my head.
I've never used unsigneds. I'd have to lok it up. Ranges in size maybe.
That's the way ints are.
There's little reason to ever use unsigneds. Some programmers use
unsigned to document that a value naturally can't be negative, like
the number of employees on a payroll. This is almost always a bad
idea.
The exception is unsigned char. It's a funny one. Really it means
"byte". It's used for storing arbitrary bits, treating them as
bit patterns rather than higher-level objects.
There are machines (e.g., IBM mainframes using EBCDIC) where normal
characters need to be unsigned (among other reasons, so the functions
in ctype.h can work).
Any code in which the signedness of a plain char is relevant, is broken
code.
Kaz Kylheku
2014-08-19 23:31:53 UTC
Permalink
Post by David Brown
Any code in which the signedness of a plain char is relevant, is broken
code.
Make that: any code or interface specification.

If char is signed, we can pull a negative value out of a simple char *
character string. This then blows up in our face when we pass it into a
<ctype.h> function like isalpha.

The signedness of char is relevant to whether there is undefined behavior
in such seemingly straightforward code as isalpha(str[i]).

If this facility were not in the language, and you coded up one exactly like it
in some C project, you'd share some blame for the shit it causes; blame would
not be 100% pinned on the programmer who naively wrote isalpha(str[i]).
David Brown
2014-08-20 00:38:23 UTC
Permalink
Post by Kaz Kylheku
Post by David Brown
Any code in which the signedness of a plain char is relevant, is broken
code.
Make that: any code or interface specification.
I agree on that.
Post by Kaz Kylheku
If char is signed, we can pull a negative value out of a simple char *
character string. This then blows up in our face when we pass it into a
<ctype.h> function like isalpha.
The signedness of char is relevant to whether there is undefined behavior
in such seemingly straightforward code as isalpha(str[i]).
If this facility were not in the language, and you coded up one exactly like it
in some C project, you'd share some blame for the shit it causes; blame would
not be 100% pinned on the programmer who naively wrote isalpha(str[i]).
If a programmer writes "isalpha(str[i])", with "str" defined as plain
chars, or isalpha taking a plain char argument, but the code only works
with plain chars being signed or only with plain chars being unsigned,
then the blame lies squarely on whoever wrote that dependency into the
code. It might be the person who wrote isalpha(), who should have made
the implementation work with either type of char or alternatively made
the interface for the function have explicit signedness. Or it might be
with the programmer who used the incorrect char type for the interface.
Either way, the blame lies with whoever made the unwarranted assumption.
Barry Schwarz
2014-08-20 04:03:42 UTC
Permalink
On Wed, 20 Aug 2014 02:38:23 +0200, David Brown
Post by David Brown
Post by Kaz Kylheku
Post by David Brown
Any code in which the signedness of a plain char is relevant, is broken
code.
Make that: any code or interface specification.
I agree on that.
Post by Kaz Kylheku
If char is signed, we can pull a negative value out of a simple char *
character string. This then blows up in our face when we pass it into a
<ctype.h> function like isalpha.
The signedness of char is relevant to whether there is undefined behavior
in such seemingly straightforward code as isalpha(str[i]).
If this facility were not in the language, and you coded up one exactly like it
in some C project, you'd share some blame for the shit it causes; blame would
not be 100% pinned on the programmer who naively wrote isalpha(str[i]).
If a programmer writes "isalpha(str[i])", with "str" defined as plain
chars, or isalpha taking a plain char argument, but the code only works
with plain chars being signed or only with plain chars being unsigned,
then the blame lies squarely on whoever wrote that dependency into the
code. It might be the person who wrote isalpha(), who should have made
the implementation work with either type of char or alternatively made
the interface for the function have explicit signedness. Or it might be
with the programmer who used the incorrect char type for the interface.
Either way, the blame lies with whoever made the unwarranted assumption.
Which is why compiler writers for EBCDIC machines make plain char
unsigned and eliminate the potential for problems..
--
Remove del for email
Barry Schwarz
2014-08-18 21:44:56 UTC
Permalink
On Mon, 18 Aug 2014 14:30:19 -0400, "Bill Cunningham"
Post by Bill Cunningham
Post by Barry Schwarz
Show your code.
I think I figure out my bug. In printing out one value being name[8].
The last charater I used in the printf format specifier %s instead if %c by
habit. Would that do it?
Since you have not shown your code and snipped any description of the
problem, one has to ask: What is "that" and what is "it"? And the
answer to your question is "no".
--
Remove del for email
Heinrich Wolf
2014-08-18 11:08:14 UTC
Permalink
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this
mbr offset. Would the proper declaration and code be,
unsigned char string[8]="MSWIN4.1";
Do you really think, the ".1" is contained in the 8 byte size array?
Post by Bill Cunningham
It looks good to me.
Bill
Do you remember the good old days of MSDOS, e.g. Ver 4. Filenames then were
%8s.%3s

Heiner
Richard Heathfield
2014-08-18 11:21:07 UTC
Permalink
<snip>
Post by Heinrich Wolf
Post by Bill Cunningham
unsigned char string[8]="MSWIN4.1";
Do you really think, the ".1" is contained in the 8 byte size array?
Why, don't you?

unsigned char string[8] gives us an array of 8 unsigned char, with valid
indices 0 to 7. They are:

string[0]: 'M'
string[1]: 'S'
string[2]: 'W'
string[3]: 'I'
string[4]: 'N'
string[5]: '4'
string[6]: '.'
string[7]: '1'

It sure looks to me like the '.' and the '1' are contained.

What is *not* contained is a null character, so this is not a string. But it
is a perfectly valid array of 8 char.

<snip>
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Keith Thompson
2014-08-18 15:26:24 UTC
Permalink
[...]
Post by Richard Heathfield
Post by Heinrich Wolf
Post by Bill Cunningham
unsigned char string[8]="MSWIN4.1";
Do you really think, the ".1" is contained in the 8 byte size array?
Why, don't you?
unsigned char string[8] gives us an array of 8 unsigned char, with valid
string[0]: 'M'
string[1]: 'S'
string[2]: 'W'
string[3]: 'I'
string[4]: 'N'
string[5]: '4'
string[6]: '.'
string[7]: '1'
It sure looks to me like the '.' and the '1' are contained.
What is *not* contained is a null character, so this is not a string. But it
is a perfectly valid array of 8 char.
<snip>
It's actually an array of unsigned char (and, as somebody else
mentioned, "string" is a bad name for it).

I had to check on this: A string literal can be used to initialize an
array of unsigned char. N1570 6.7.9p14:

An array of character type may be initialized by a character
string literal [...]. Successive bytes of the string literal
(including the terminating null character if there is room or
if the array is of unknown size) initialize the elements of
the array.

So this:

unsigned char pick_a_better_name[8]="MSWIN4.1";

is legal, and equivalent to this:

unsigned char pick_a_better_name[8]
= { 'M', 'S', 'W', 'I', 'N', '4', '.', '1' };

On the other hand, this:

unsigned char *ptr = "MSWIN4.1";

is a constraint violation, since it tries to initialize an unsigned
char* object with a value of type char*. It might be nice to have
a string literal syntax for arrays of unsigned char (likewise for
signed char), but as of C11 the u"..." syntax is already taken for
arrays of char16_t.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Richard Heathfield
2014-08-18 16:19:25 UTC
Permalink
<snip>
Post by Keith Thompson
Post by Richard Heathfield
unsigned char string[8] gives us an array of 8 unsigned char, with valid
indices 0 to 7.
<snip>
Post by Keith Thompson
It's actually an array of unsigned char
But with one judicious and highly selective snip, he was free!




Seriously... clearly I knew that (see above). Equally clearly, I was not as
careful as I should have been in subsequent text, for which I apologise.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Bill Cunningham
2014-08-18 18:32:33 UTC
Permalink
Welcome back Richard!

Bill
Joe Pfeiffer
2014-08-18 14:40:24 UTC
Permalink
Post by Heinrich Wolf
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is
an 8 byte size "string". All ints according to this "whitepaper"
some my know what I'm talking about. Says all ints and
unsigned. Clear enough. It says nothing about chars. MSWIN4.1 is the
recommended string to place at this mbr offset. Would the proper
declaration and code be,
unsigned char string[8]="MSWIN4.1";
Do you really think, the ".1" is contained in the 8 byte size array?
I can't speak for Bill, but if they aren't then you're picking up on
something I'm missing. What are you seeing here?
Post by Heinrich Wolf
Post by Bill Cunningham
It looks good to me.
Bill
Do you remember the good old days of MSDOS, e.g. Ver 4. Filenames then
were %8s.%3s
Are you confusing the format of a filename with the contents of the MBR?
Charles Richmond
2014-08-18 20:33:53 UTC
Permalink
Post by Joe Pfeiffer
Post by Heinrich Wolf
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is
an 8 byte size "string". All ints according to this "whitepaper"
some my know what I'm talking about. Says all ints and
unsigned. Clear enough. It says nothing about chars. MSWIN4.1 is the
recommended string to place at this mbr offset. Would the proper
declaration and code be,
unsigned char string[8]="MSWIN4.1";
Do you really think, the ".1" is contained in the 8 byte size array?
I can't speak for Bill, but if they aren't then you're picking up on
something I'm missing. What are you seeing here?
Perhaps I am misunderstanding here, but ISTM if we are talking about the
FAT12 floppy disk format: file names are stored *without* storing the "."
That way the file entry only needs 11 bytes for the file name. In the
directory space, here are 11 bytes reserved for each file, even if the file
name is shorter. The last three bytes represent the file name extension...
the part to the right of the "." Unused bytes are blank filled.

So the file "ROGER.C" would be stored in the directory as
"ROGER<space><space><space>C<space><space>".
--
numerist at aquaporin4 dot com
James Kuyper
2014-08-18 21:08:25 UTC
Permalink
Post by Charles Richmond
Post by Joe Pfeiffer
Post by Heinrich Wolf
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is
an 8 byte size "string". All ints according to this "whitepaper"
some my know what I'm talking about. Says all ints and
unsigned. Clear enough. It says nothing about chars. MSWIN4.1 is the
recommended string to place at this mbr offset. Would the proper
declaration and code be,
unsigned char string[8]="MSWIN4.1";
Do you really think, the ".1" is contained in the 8 byte size array?
I can't speak for Bill, but if they aren't then you're picking up on
something I'm missing. What are you seeing here?
Perhaps I am misunderstanding here, but ISTM if we are talking about the
FAT12 floppy disk format: file names are stored *without* storing the "."
The only array of any kind mentioned in Bill's message was the one
mis-named 'string', and the only occurrence of ".1" is was in the
initializer for that array. If you were talking about some other array,
not visible in Bill's message, you should have identified it.
He did not show the code that makes a connection between his array and
the FAT. He's almost certainly barking up the wrong tree with his
approach, but we haven't actually seen what his approach is.
Barry Schwarz
2014-08-18 22:04:07 UTC
Permalink
On Mon, 18 Aug 2014 15:33:53 -0500, "Charles Richmond"
<***@aquaporin4.com> wrote:

<snip>
Post by Charles Richmond
Perhaps I am misunderstanding here, but ISTM if we are talking about the
FAT12 floppy disk format: file names are stored *without* storing the "."
That way the file entry only needs 11 bytes for the file name. In the
Yes you misunderstand. Bill is looking at one description of the boot
sector of a volume organized with a FAT. But the discussion is about
his inability to generate C code that accesses various parts of an
array of 8 char that does not contain a C-style string.
--
Remove del for email
Joe Pfeiffer
2014-08-18 23:12:50 UTC
Permalink
Post by Charles Richmond
Post by Joe Pfeiffer
Post by Heinrich Wolf
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is
an 8 byte size "string". All ints according to this "whitepaper"
some my know what I'm talking about. Says all ints and
unsigned. Clear enough. It says nothing about chars. MSWIN4.1 is the
recommended string to place at this mbr offset. Would the proper
declaration and code be,
unsigned char string[8]="MSWIN4.1";
Do you really think, the ".1" is contained in the 8 byte size array?
I can't speak for Bill, but if they aren't then you're picking up on
something I'm missing. What are you seeing here?
Perhaps I am misunderstanding here, but ISTM if we are talking about
the FAT12 floppy disk format: file names are stored *without* storing
the "." That way the file entry only needs 11 bytes for the file name.
In the directory space, here are 11 bytes reserved for each file, even
if the file name is shorter. The last three bytes represent the file
name extension... the part to the right of the "." Unused bytes are
blank filled.
So the file "ROGER.C" would be stored in the directory as
"ROGER<space><space><space>C<space><space>".
But he isn't talking about filenames. He's talking about the OEM Name
in the FAT boot record.
Michael Angelo Ravera
2014-08-19 09:31:59 UTC
Permalink
Post by Bill Cunningham
I have been looking at FATxx mbr offsets and data. At offset 3 is an 8
byte size "string". All ints according to this "whitepaper" some my know
what I'm talking about. Says all ints and unsigned. Clear enough. It says
nothing about chars. MSWIN4.1 is the recommended string to place at this mbr
offset. Would the proper declaration and code be,
unsigned char string[8]="MSWIN4.1";
It looks good to me.
It looks good to you because you have either a blind spot, mental block, or fundamental lack of understanding when it comes to entire subject of Data Representation. Try typing "Fundamentals of data representation" into your favorite search engine and reading up until you understand the subject or taking a fifth grade computing science class. How about writing an assembly language program that takes as input a list of numbers, displays them forwards and backwards, and computes the sum? Now when you write it in C you will know what you are doing.

I have told you before and I will tell you again. C is relatively easy for people who understand data representation and almost impossible for those who don't. So, if you want to write in C, learn data representation.
Loading...