Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #99491 > unrolled thread
| Started by | Alla _ <modelling.data@gmail.com> |
|---|---|
| First post | 2016-12-15 05:05 -0800 |
| Last post | 2016-12-16 11:46 +0000 |
| Articles | 20 on this page of 72 — 11 participants |
Back to article view | Back to comp.lang.c
Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-15 05:05 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 13:48 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-15 08:22 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 16:28 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-15 09:25 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 19:31 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 01:19 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 10:01 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 02:43 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 11:03 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 03:08 -0800
Re: Program to read csv file, store characters and numbers in separate arrays jameskuyper@verizon.net - 2016-12-18 03:32 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Barry Schwarz <schwarzb@dqel.com> - 2016-12-16 17:09 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 01:25 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 10:11 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 02:45 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Keith Thompson <kst-u@mib.org> - 2016-12-16 09:54 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 17:56 +0000
Re: Program to read csv file, store characters and numbers in separate arrays gazelle@shell.xmission.com (Kenny McCormack) - 2016-12-16 18:02 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 03:06 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 11:28 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-12-16 12:02 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 12:41 +0000
Re: Program to read csv file, store characters and numbers in separate arrays BartC <bc@freeuk.com> - 2016-12-16 13:40 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 14:03 +0000
Re: Program to read csv file, store characters and numbers in separate arrays BartC <bc@freeuk.com> - 2016-12-16 13:03 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-12-16 15:04 +0000
Re: Program to read csv file, store characters and numbers in separate arrays BartC <bc@freeuk.com> - 2016-12-16 15:26 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-12-16 17:01 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 04:18 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 14:12 +0000
Re: Program to read csv file, store characters and numbers in separate arrays David Brown <david.brown@hesbynett.no> - 2016-12-15 16:14 +0100
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 15:37 +0000
Re: Program to read csv file, store characters and numbers in separate arrays David Brown <david.brown@hesbynett.no> - 2016-12-15 23:20 +0100
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 23:27 +0000
Re: Program to read csv file, store characters and numbers in separate arrays David Brown <david.brown@hesbynett.no> - 2016-12-16 12:10 +0100
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 11:43 +0000
Re: Program to read csv file, store characters and numbers in separate arrays David Brown <david.brown@hesbynett.no> - 2016-12-16 14:01 +0100
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 13:12 +0000
Re: Program to read csv file, store characters and numbers in separate arrays David Brown <david.brown@hesbynett.no> - 2016-12-16 14:57 +0100
Re: Program to read csv file, store characters and numbers in separate arrays BartC <bc@freeuk.com> - 2016-12-15 16:30 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 16:36 +0000
Re: Program to read csv file, store characters and numbers in separate arrays David Brown <david.brown@hesbynett.no> - 2016-12-15 23:29 +0100
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-15 08:26 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 16:33 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-15 08:32 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 16:37 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Keith Thompson <kst-u@mib.org> - 2016-12-15 12:17 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 01:33 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Keith Thompson <kst-u@mib.org> - 2016-12-15 12:23 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-15 20:39 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-12-15 21:13 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 00:39 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 08:54 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 01:09 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 09:32 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 01:51 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 10:08 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-12-16 11:09 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 03:16 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 03:20 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Keith Thompson <kst-u@mib.org> - 2016-12-16 09:48 -0800
Re: Program to read csv file, store characters and numbers in separate arrays gazelle@shell.xmission.com (Kenny McCormack) - 2016-12-16 17:55 +0000
Re: Program to read csv file, store characters and numbers in separate arrays raltbos@xs4all.nl (Richard Bos) - 2016-12-20 11:53 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 11:33 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Keith Thompson <kst-u@mib.org> - 2016-12-16 09:46 -0800
Re: Program to read csv file, store characters and numbers in separate arrays "James R. Kuyper" <jameskuyper@verizon.net> - 2017-01-03 15:38 -0500
Re: Program to read csv file, store characters and numbers in separate arrays Barry Schwarz <schwarzb@dqel.com> - 2016-12-15 12:36 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 01:44 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 10:04 +0000
Re: Program to read csv file, store characters and numbers in separate arrays Alla _ <modelling.data@gmail.com> - 2016-12-16 03:14 -0800
Re: Program to read csv file, store characters and numbers in separate arrays Richard Heathfield <rjh@cpax.org.uk> - 2016-12-16 11:46 +0000
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-16 11:28 +0000 |
| Message-ID | <o30j33$8po$1@dont-email.me> |
| In reply to | #99628 |
On 16/12/16 11:06, Alla _ wrote:
> On Friday, December 16, 2016 at 1:11:58 PM UTC+3, Richard Heathfield wrote:
>> On 16/12/16 09:25, Alla _ wrote:
>>> On Thursday, December 15, 2016 at 10:31:28 PM UTC+3, Richard Heathfield wrote:
>>>> On 15/12/16 17:25, Alla _ wrote:
> <snip>
>> Hex dump, please.
>>
> Below I post:
> (1) The corrected version of the program based on comments I have received;
I will make only one comment on the program, because I think first we
need to sort out your data.
> (2) csv inputs
> (3) program's outputs
> (4) hex dumps for each csv
> Interesting: now that I have changed the error checking method, i.e. if (!ferror(fp)),
> instead of checking for !feof, I get the error message at the end of the whole output;
> this is telling me that there is something wrong with every csv file.
Yeah, your logic says:
IF there is NOT an error
Report an error
Remove the !
>
> (2) File you have sent me (without changing Income
> statement to Years in the first row):
>
> ******csv file******
> Income Statement,2011,2012,2013,2014,2015
This is the line we care about, because:
> ******code output with one trailing zero******
> (3) 2011 2012 2013 2014 2015 0
...here is our first trailing zero. So let's look at the data up to that
point, using a hex dump.
> ******hex******
> 49 6E 63 6F 6D 65 20 53 74 61 74 65 6D 65 6E 74
> 2C 32 30 31 31 2C 32 30 31 32 2C 32 30 31 33 2C
> 32 30 31 34 2C 32 30 31 35 0D 0A
There's your problem right there. 0D 0A instead of just 0A.
On Windows, 0D 0A is a correct line-end indicator. On Linux and on
modern Macs, 0A is the right indicator. So your copy of Excel is
preparing its CSV file for use on Windows, when it *should* be preparing
it for use on the host system.
Here is a simple filter for you to use:
#include <stdio.h>
int main(void)
{
int ch;
while((ch = getchar()) != EOF)
{
if(ch != '\r')
{
putchar(ch);
}
}
return 0;
}
Usage:
./dos2unix < input.csv > output.csv
Removes all carriage returns from the file.
You might already have a dos2unix program on your system, in which case
by all means use that.
--
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
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-12-16 12:02 +0000 |
| Message-ID | <87a8bw2iai.fsf@bsb.me.uk> |
| In reply to | #99637 |
Richard Heathfield <rjh@cpax.org.uk> writes:
<snip>
> ...here is our first trailing zero. So let's look at the data up to
> that point, using a hex dump.
>
>> ******hex******
>> 49 6E 63 6F 6D 65 20 53 74 61 74 65 6D 65 6E 74
>> 2C 32 30 31 31 2C 32 30 31 32 2C 32 30 31 33 2C
>> 32 30 31 34 2C 32 30 31 35 0D 0A
>
> There's your problem right there. 0D 0A instead of just 0A.
>
> On Windows, 0D 0A is a correct line-end indicator. On Linux and on
> modern Macs, 0A is the right indicator. So your copy of Excel is
> preparing its CSV file for use on Windows, when it *should* be
> preparing it for use on the host system.
Well, should is a matter of opinion. Here is at least one opinion about
what a CSV file is:
1. Each record is located on a separate line, delimited by a line
break (CRLF). For example:
aaa,bbb,ccc CRLF
zzz,yyy,xxx CRLF
This is from RFC 4180 (don't worry, it does explain that fields can span
lines later on). In a court of law you could well argue that MS Excel
is doing the right thing here. Whilst you may well say it should not do
this, it is certain that if it didn't, someone else will say that they
definitely should.
CSV files have no universally agreed separator (despite the name), no
universally agreed character encoding, no universally agreed line ending
and no universally agreed quoting scheme. The only universally agreed
thing about them is that they are a pain in neck.
The sound advice about file formats: "be generous in what your code
accepts and strict in what it generates" is almost impossible to follow
here, but it would certainly require the file to be processed as a
binary stream.
Normally, for a beginner, all this unfortunate mess can be glossed over,
but if the files are being generated with CRLF endings it would appear
that it can't be avoided here.
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-16 12:41 +0000 |
| Message-ID | <o30nak$nd9$1@dont-email.me> |
| In reply to | #99641 |
On 16/12/16 12:02, Ben Bacarisse wrote:
> Richard Heathfield <rjh@cpax.org.uk> writes:
<snip>
>> On Windows, 0D 0A is a correct line-end indicator. On Linux and on
>> modern Macs, 0A is the right indicator. So your copy of Excel is
>> preparing its CSV file for use on Windows, when it *should* be
>> preparing it for use on the host system.
>
> Well, should is a matter of opinion. Here is at least one opinion about
> what a CSV file is:
>
> 1. Each record is located on a separate line, delimited by a line
> break (CRLF). For example:
>
> aaa,bbb,ccc CRLF
> zzz,yyy,xxx CRLF
>
> This is from RFC 4180
I take your point, but let's look at the context:
While there are various specifications and implementations for the
CSV format (for ex. [4], [5], [6] and [7]), there is no formal
specification in existence, which allows for a wide variety of
interpretations of CSV files. This section documents the format that
seems to be followed by most implementations:
1. Each record is located on a separate line, delimited by a line
break (CRLF).
So it is reporting what the author /believes/ to be the practice
followed by /most/ implementations. And I doubt very much whether Y
Shafranovich stopped to consider whether that was the practice followed
on *nix-like systems. Furthermore, the disclaimer at the top of the
document makes it clear that this is *not* even an Internet standard,
let alone a general computing standard.
CRLF is often specified in RFCs, and it can surely only be a sop to
Microsoft. I can think of no other reason for it, anyway. If MS would
only do the decent thing and drop this ridiculous convention, a whole
universe of pain could be avoided.
> (don't worry, it does explain that fields can span
> lines later on). In a court of law you could well argue that MS Excel
> is doing the right thing here. Whilst you may well say it should not do
> this, it is certain that if it didn't, someone else will say that they
> definitely should.
>
> CSV files have no universally agreed separator (despite the name), no
> universally agreed character encoding, no universally agreed line ending
> and no universally agreed quoting scheme. The only universally agreed
> thing about them is that they are a pain in neck.
Well, that's certainly true. No doubt we all have our own preferences.
Personally, if I have the choice, I choose tab separators, \n line
endings, and straight ASCII encoding, high bit always clear. (Obviously
that isn't going to suit everybody.)
> The sound advice about file formats: "be generous in what your code
> accepts and strict in what it generates" is almost impossible to follow
> here, but it would certainly require the file to be processed as a
> binary stream.
>
> Normally, for a beginner, all this unfortunate mess can be glossed over,
> but if the files are being generated with CRLF endings it would appear
> that it can't be avoided here.
Easy to fix, though - dos2unix will do it.
--
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
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-12-16 13:40 +0000 |
| Message-ID | <o30qpa$3jg$1@dont-email.me> |
| In reply to | #99644 |
On 16/12/2016 12:41, Richard Heathfield wrote: > CRLF is often specified in RFCs, and it can surely only be a sop to > Microsoft. I can think of no other reason for it, anyway. I think CRLF was around long before Microsoft. Something to do with driving a teletype I understand. > If MS would > only do the decent thing and drop this ridiculous convention, a whole > universe of pain could be avoided. If the main line-endings are either CRLF or LF (and you disallow individual LF or CR within text that were once used for cursor control) then it isn't much problem to deal with either convention. My programs do that and since then I've never had a problem with my editor for example dealing with either kind of file (unlike Notepad). I find dealing properly with tabs is a bigger problem. > Easy to fix, though - dos2unix will do it. That's funny, I used to have a program called ADDCR to do the opposite. Which I no longer need. -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-16 14:03 +0000 |
| Message-ID | <o30s58$88l$2@dont-email.me> |
| In reply to | #99649 |
On 16/12/16 13:40, BartC wrote: > On 16/12/2016 12:41, Richard Heathfield wrote: > >> CRLF is often specified in RFCs, and it can surely only be a sop to >> Microsoft. I can think of no other reason for it, anyway. > > I think CRLF was around long before Microsoft. Something to do with > driving a teletype I understand. Yes, that's right. I didn't say they invented it. I said they should stop using it. Either that, or they should invest in a buggy whip factory. >> If MS would >> only do the decent thing and drop this ridiculous convention, a whole >> universe of pain could be avoided. > > If the main line-endings are either CRLF or LF (and you disallow > individual LF or CR within text that were once used for cursor control) > then it isn't much problem to deal with either convention. Of course not, if you know about it and know how to deal with it. It's still a nuisance, though. -- 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
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-12-16 13:03 +0000 |
| Message-ID | <o30oks$rn1$1@dont-email.me> |
| In reply to | #99641 |
On 16/12/2016 12:02, Ben Bacarisse wrote: > Well, should is a matter of opinion. Here is at least one opinion about > what a CSV file is: > > 1. Each record is located on a separate line, delimited by a line > break (CRLF). For example: > > aaa,bbb,ccc CRLF > zzz,yyy,xxx CRLF > > This is from RFC 4180 (don't worry, it does explain that fields can span > lines later on). Big mistake. Apparently leading and trailing spaces are also significant. This means that a big chunk of a file spanning multiple lines containing English prose, or function of a programming language, counts as just one CSV field so long as there aren't any commas in there. (And apparently a quoted field can still contain unadorned newline characters. So even fgets can only retrieve part of a field. Such characters should be escaped. Newline should be a higher level separator than comma.) > CSV files have no universally agreed separator (despite the name), no > universally agreed character encoding, no universally agreed line ending > and no universally agreed quoting scheme. The only universally agreed > thing about them is that they are a pain in neck. If your program generates CSV then you can do it properly so that you can read your own files and make it more likely for them to be acceptable to other programs. But you might still have the headache of dealing with embedded special characters within a field. > The sound advice about file formats: "be generous in what your code > accepts and strict in what it generates" Oh, that's what I just repeated... -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-12-16 15:04 +0000 |
| Message-ID | <874m233ogi.fsf@bsb.me.uk> |
| In reply to | #99646 |
BartC <bc@freeuk.com> writes: > On 16/12/2016 12:02, Ben Bacarisse wrote: > >> Well, should is a matter of opinion. Here is at least one opinion about >> what a CSV file is: >> >> 1. Each record is located on a separate line, delimited by a line >> break (CRLF). For example: >> >> aaa,bbb,ccc CRLF >> zzz,yyy,xxx CRLF >> >> This is from RFC 4180 (don't worry, it does explain that fields can span >> lines later on). > > Big mistake. Apparently leading and trailing spaces are also > significant. I'm not sure what the mistake is. Can you explain? > This means that a big chunk of a file spanning multiple lines > containing English prose, or function of a programming language, > counts as just one CSV field so long as there aren't any commas in > there. I know this is meant to explain the "big mistake" but I still don't see it. I don't think commas are really an issue since in every CSV format I've seen fields with multiple lines have to be quoted. But since there can be two kind of "line" in a CSV file, it's possible that commas might come into it, but I'm not sure that's what you mean. For example, in a file with CRLF line endings, I can imagine a really nasty CSV file with multi-line text whose line separator is LF: f1,f2,thisLFisLFfourLFlinesCRLF (I don't know it any software either write this or reads it, but I can imagine it being possible in some badly specified formats.) > (And apparently a quoted field can still contain unadorned newline > characters. So even fgets can only retrieve part of a field. Such > characters should be escaped. Newline should be a higher level > separator than comma.) Yes. You should not use fgets to read binary files. You /can/, of course, but I can't see the point other than give yourself a lot of pain. >> CSV files have no universally agreed separator (despite the name), no >> universally agreed character encoding, no universally agreed line ending >> and no universally agreed quoting scheme. The only universally agreed >> thing about them is that they are a pain in neck. > > If your program generates CSV then you can do it properly so that you > can read your own files and make it more likely for them to be > acceptable to other programs. But you might still have the headache of > dealing with embedded special characters within a field. > >> The sound advice about file formats: "be generous in what your code >> accepts and strict in what it generates" > > Oh, that's what I just repeated... Yes, though I went on to say that it's almost impossible to do. Your "you can do it properly" makes it sound easy. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-12-16 15:26 +0000 |
| Message-ID | <o31112$paq$1@dont-email.me> |
| In reply to | #99655 |
On 16/12/2016 15:04, Ben Bacarisse wrote: >> Big mistake. Apparently leading and trailing spaces are also >> significant. > > I'm not sure what the mistake is. Can you explain? > >> This means that a big chunk of a file spanning multiple lines >> containing English prose, or function of a programming language, >> counts as just one CSV field so long as there aren't any commas in >> there. > > I know this is meant to explain the "big mistake" but I still don't see > it. The mistake is having 'comma' be more important than 'newline'. Which can also make this ambiguous: abc,def ghi,jkl Under strict CSV interpretation, that could be one record with three fields: abc,def\nghi,jkl If you know the number of fields, that might help disambiguate. But CSV files usually don't state that. > I don't think commas are really an issue since in every CSV format I've > seen fields with multiple lines have to be quoted. That doesn't really help. If the above example really was 3 fields, then quoting it would produce this: abc,"def ghi",jkl There is still a 'hard' newline character in the middle of the field. Generic line-oriented text-handling, including fgets, will read that as two separate lines. Fiddly CSV-aware code, or that handles this stuff as s low-level character-at-a-time stream, might be able to handle that. But you want to keep it simple. For example, a routine to copy a CSV file and tack an extra field on the end of each line would be trivial if it wasn't for that fact that some newlines could be embedded elements of some fields. >> (And apparently a quoted field can still contain unadorned newline >> characters. So even fgets can only retrieve part of a field. Such >> characters should be escaped. Newline should be a higher level >> separator than comma.) > > Yes. You should not use fgets to read binary files. CSV is a text format, not binary. That's the point of CSV. From what I can find out, there isn't an escape scheme for embedded control characters, as would be needed in string literals in source code for example. >> If your program generates CSV then you can do it properly so that you >> can read your own files and make it more likely for them to be >> acceptable to other programs. > Yes, though I went on to say that it's almost impossible to do. Your > "you can do it properly" makes it sound easy. Easy to write and re-read your own files. Well, it's a little more fiddly if you allow that some character fields can contain non-printable characters (or separators or whitespace) as you need to invent or import a string escape scheme. -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-12-16 17:01 +0000 |
| Message-ID | <87mvfv24fs.fsf@bsb.me.uk> |
| In reply to | #99658 |
BartC <bc@freeuk.com> writes: > On 16/12/2016 15:04, Ben Bacarisse wrote: > >>> Big mistake. Apparently leading and trailing spaces are also >>> significant. >> >> I'm not sure what the mistake is. Can you explain? >> >>> This means that a big chunk of a file spanning multiple lines >>> containing English prose, or function of a programming language, >>> counts as just one CSV field so long as there aren't any commas in >>> there. >> >> I know this is meant to explain the "big mistake" but I still don't see >> it. > > The mistake is having 'comma' be more important than 'newline'. Which > can also make this ambiguous: > > abc,def > ghi,jkl > > Under strict CSV interpretation, that could be one record with three fields: > > abc,def\nghi,jkl I don't know why you think that. As far as I know, unquoted line ending are record separators. Of course, any CSV specification that had this ambiguity would indeed be a big mistake but I don't know how you got there from what I quoted. > If you know the number of fields, that might help disambiguate. But > CSV files usually don't state that. > >> I don't think commas are really an issue since in every CSV format I've >> seen fields with multiple lines have to be quoted. > > That doesn't really help. If the above example really was 3 fields, > then quoting it would produce this: > > abc,"def > ghi",jkl > > There is still a 'hard' newline character in the middle of the > field. Generic line-oriented text-handling, including fgets, will read > that as two separate lines. If you read a CSV file with fgets you need to handle (or, I suppose, ignore) the complications that leads to. Bit since the most general form of CSV file should be read as a binary stream (in the sense that you can't assume your system's line ending will be used) reading it with fgets is a really bad idea (though even that could be made to work). > Fiddly CSV-aware code, or that handles this stuff as s low-level > character-at-a-time stream, might be able to handle that. But you want > to keep it simple. For example, a routine to copy a CSV file and tack > an extra field on the end of each line would be trivial if it wasn't > for that fact that some newlines could be embedded elements of some > fields. If you know the line ending and the quoting method used, that's not really hard (maybe the other side of trival, but not hard). If you don't know the quoting method or the line ending, it's impossible. CSV is a mess. >>> (And apparently a quoted field can still contain unadorned newline >>> characters. So even fgets can only retrieve part of a field. Such >>> characters should be escaped. Newline should be a higher level >>> separator than comma.) >> >> Yes. You should not use fgets to read binary files. > > CSV is a text format, not binary. I'm using C's terminology here. It's a binary file in that you don't want to apply your host system's line-end translation to the IO. You /can/ treat a CSV file as a text file, but I've found that to be a bad idea in general. > That's the point of CSV. From what I > can find out, there isn't an escape scheme for embedded control > characters, as would be needed in string literals in source code for > example. Yes, in everyday tech. language it's a text format, but you should read CSV files (for best results) as binary streams in C. >>> If your program generates CSV then you can do it properly so that you >>> can read your own files and make it more likely for them to be >>> acceptable to other programs. > >> Yes, though I went on to say that it's almost impossible to do. Your >> "you can do it properly" makes it sound easy. > > Easy to write and re-read your own files. Yes, that's certainly easy. > Well, it's a little more > fiddly if you allow that some character fields can contain > non-printable characters (or separators or whitespace) as you need to > invent or import a string escape scheme. And it's way more than fiddly if you need to be able to read, correctly, every CSV file out there as well write CSV files that can be read by every CSV reader out there. That's the "almost impossible" I was referring to. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Alla _ <modelling.data@gmail.com> |
|---|---|
| Date | 2016-12-16 04:18 -0800 |
| Message-ID | <8ac2c0e7-56ee-4c80-b2c5-2e7d3a959b10@googlegroups.com> |
| In reply to | #99637 |
On Friday, December 16, 2016 at 2:29:02 PM UTC+3, Richard Heathfield wrote: > On 16/12/16 11:06, Alla _ wrote: > > On Friday, December 16, 2016 at 1:11:58 PM UTC+3, Richard Heathfield wrote: > >> On 16/12/16 09:25, Alla _ wrote: > >>> On Thursday, December 15, 2016 at 10:31:28 PM UTC+3, Richard Heathfield wrote: > >>>> On 15/12/16 17:25, Alla _ wrote: > > <snip> > >> Hex dump, please. > >> > > Below I post: > > (1) The corrected version of the program based on comments I have received; > > I will make only one comment on the program, because I think first we > need to sort out your data. > > > (2) csv inputs > > (3) program's outputs > > (4) hex dumps for each csv > > Interesting: now that I have changed the error checking method, i.e. if (!ferror(fp)), > > instead of checking for !feof, I get the error message at the end of the whole output; > > this is telling me that there is something wrong with every csv file. > > Yeah, your logic says: > > IF there is NOT an error > Report an error oops! ))) I have no idea how that ! has appeared there ) > <snip>
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-15 14:12 +0000 |
| Message-ID | <o2u8a9$3n0$1@dont-email.me> |
| In reply to | #99491 |
[the code]
On 15/12/16 13:05, Alla _ wrote:
> (3) I will use a header file, in which I will store preprocessor commands, like
> #define and #include, as well as functions' declarations, etc.;
A well-designed header contains *only* the following:
1) inclusion guards;
2) macro definitions (#defines);
3) type definitions (typedefs);
4) function prototypes;
5) comments;
6) #include directives *ONLY* for those headers that are required for
the immediate purposes of the header itself.
For example, here's a quick header I threw together a year or so ago:
/* CISPRNG - Cryptographically In-Secure
* Pseudo-Random Number Generator
*
* Written by Richard Heathfield,
* 20 October 2015.
*
* You will also need cisprng.c and a
* C compiler.
*
* The author places this code into the
* public domain, and so it may be freely
* used for any legal purpose, although
* I would recommend against using it
* in circumstances where you really need
* a cryptographically secure PRNG, because
* it isn't one.
*/
#ifndef H_CISPRNG_H_
#define H_CISPRNG_H_
#define CISPRNG_RAND_MAX (0x7FFFFFFFUL)
/* Single state versions */
/* set the seed */
void cisprng_set(unsigned long seed);
/* get a PRN */
unsigned long cisprng_random(void);
/* get a PRN in a range */
unsigned long cisprng_range(unsigned long low,
unsigned long high);
/* Custom state versions */
unsigned long cisprng_csrandom(unsigned long *pseed);
unsigned long cisprng_csrange(unsigned long *pseed,
unsigned long low,
unsigned long high);
#endif
/* end of cisprng.h */
Note that it doesn't define any types. But if it did, they would go
after the #defines but before the function prototypes. Nor does it
include any headers. But *if* I'd used, say, size_t *in the header*, I'd
have included <stddef.h> in the header. But I would *not* include
<stddef.h> in the header just because the corresponding C file used
size_t (which, actually, it doesn't). A module header is not a place to
hide #includes.
> #include <stdio.h>
> #include <stdlib.h>
> #include <ctype.h>
> #include <string.h>
>
>
> #define BUFFER_SIZE 100
> //#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
> #define INCOME_STATEMENT "files/income_test.csv"
>
> int main(int argc, char *argv[])
> {
> //check for correct number of arguments
> if(argc > 2)
> {
> printf("Usage: program_name [file_name]");
You might want a \n on there. Or use puts() instead if you prefer.
Otherwise, this happens:
Usage: program_name [file_name]me@mymachine$
which probably isn't what you wanted to see.
> return EXIT_FAILURE;
> }
> //determine a file to use
> char *data_file = (argc == 2)? argv[1] : INCOME_STATEMENT;
I don't suppose you plan to change the filename, so why not make this const?
const char *data_file = (argc == 2)? argv[1] : INCOME_STATEMENT;
This will remove the *only* diagnostic message that gcc gave me (and by
the way, to get only one warning when using my flag choices is quite an
achievement!).
What should the program do if there are several arguments? At the
moment, if I tell it:
./alla test1.csv test2.csv
I get this message:
Usage: program_name [file_name]
If the program can only handle one data file, I would expect to see
something like:
Sorry, I can only process one file. Ignoring subsequent arguments...
which you would code like this:
const char *data_file = (argc > 1)? argv[1] : INCOME_STATEMENT;
if(argc > 2)
{
fputs("Sorry, I can only process one file."
" Ignoring subsequent arguments...\n",
stderr);
}
>
> FILE *fp = fopen(data_file, "r");
>
> if ( fp )
> {
> char buffer[BUFFER_SIZE] = "";
> char array_names[50][50];
> int array_values[50][50];
I am taking you at your word and forbearing to comment on these values,
but for the sake of a predictable life I would suggest that you
initialise these two arrays:
char array_names[50][50] = {0};
int array_values[50][50] = {0};
which will take advantage of the default static initialisation rule to
set everything to 0.
> char *ptr_buffer = NULL;
> size_t i, j, k;
>
> //Read each line from the file, store in the buffer
> for ( i = 0; fgets(buffer, sizeof(buffer), fp) != NULL; ++i )
Since i isn't part of the loop control logic, I would suggest that you
replace this line with the much more usual:
i = 0;
while(fgets(buffer, sizeof buffer, fp) != NULL)
{
/* stuff */
i++;
}
And if i is a line number, why not call it line_number? That's much more
descriptive than i.
The loop body looked more or less okay to me, except that it's a touch
on the large side. Think about functional decomposition.
> if (!feof(fp))
> {
> puts("Something went wrong with the provided file\n");
> return EXIT_FAILURE;
> }
Why not use ferror(fp) instead? It's a more direct description of what
you're trying to find out:
if(ferror(fp))
{
And while we're on the subject, diagnostic messages sit much better on
stderr than on stdout. That way, they can be separated from the
program's normal output, like this:
./alla test1.csv > test1.out 2> test1.log
which will put stdout stuff into test1.out and stderr stuff into test1.log.
--
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
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-12-15 16:14 +0100 |
| Message-ID | <o2ubtq$hb6$1@dont-email.me> |
| In reply to | #99496 |
On 15/12/16 15:12, Richard Heathfield wrote: > [the code] > > On 15/12/16 13:05, Alla _ wrote: > >> (3) I will use a header file, in which I will store preprocessor >> commands, like >> #define and #include, as well as functions' declarations, etc.; > > A well-designed header contains *only* the following: > > 1) inclusion guards; > 2) macro definitions (#defines); > 3) type definitions (typedefs); > 4) function prototypes; > 5) comments; > 6) #include directives *ONLY* for those headers that are required for > the immediate purposes of the header itself. > > For example, here's a quick header I threw together a year or so ago: > > /* CISPRNG - Cryptographically In-Secure > * Pseudo-Random Number Generator > * > * Written by Richard Heathfield, > * 20 October 2015. > * > * You will also need cisprng.c and a > * C compiler. > * > * The author places this code into the > * public domain, and so it may be freely > * used for any legal purpose, although > * I would recommend against using it > * in circumstances where you really need > * a cryptographically secure PRNG, because > * it isn't one. > */ > #ifndef H_CISPRNG_H_ > #define H_CISPRNG_H_ > > #define CISPRNG_RAND_MAX (0x7FFFFFFFUL) > > /* Single state versions */ > /* set the seed */ > void cisprng_set(unsigned long seed); > /* get a PRN */ > unsigned long cisprng_random(void); > /* get a PRN in a range */ > unsigned long cisprng_range(unsigned long low, > unsigned long high); > /* Custom state versions */ > unsigned long cisprng_csrandom(unsigned long *pseed); > unsigned long cisprng_csrange(unsigned long *pseed, > unsigned long low, > unsigned long high); > #endif > /* end of cisprng.h */ > > Note that it doesn't define any types. But if it did, they would go > after the #defines but before the function prototypes. Nor does it > include any headers. But *if* I'd used, say, size_t *in the header*, I'd > have included <stddef.h> in the header. But I would *not* include > <stddef.h> in the header just because the corresponding C file used > size_t (which, actually, it doesn't). A module header is not a place to > hide #includes. > I hope I am not going to cause too much confusion to a learner here, but I have a few comments about your rules for headers. It may be that you agree with me, and just did not write your complete rule set. I think it is important to emphasis that you should only have macros, types, function prototypes, etc., in a header if these declarations will be used by other modules. Anything that is used only within the implementation C file, should be in that file alone - and not the header. So if you have a function "cisprng_calculate" that is not exported, it should not be declared in the header file, and it should be declared "static" in the C file. Regarding macros, I would always limit the use of macros to when you actually need them to be macros. If usage of CISPRNG_RAND_MAX permits, I would prefer: static const unsigned long int cisprng_rand_max = 0x7ffffffful; The rules of "const" objects in C mean that you often /do/ need to make such things #define'd values rather than static consts. Assuming you are using C99 or C11 rather than C90 (I know some people still use C90), then "static inline" functions are often a better alternative to function-like macros, and can go in headers as well. I would also put more emphasis on the comments. Ideally, the comments in a header should tell the reader all they need to know about the functions and how to use them. It makes it easier for people using the code - they don't have to look elsewhere for documentation. Of course, there are limits - comments should not be so extensive that it is hard to see the code!
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-15 15:37 +0000 |
| Message-ID | <o2uda0$mjd$1@dont-email.me> |
| In reply to | #99503 |
On 15/12/16 15:14, David Brown wrote: > On 15/12/16 15:12, Richard Heathfield wrote: >> [the code] >> >> On 15/12/16 13:05, Alla _ wrote: >> >>> (3) I will use a header file, in which I will store preprocessor >>> commands, like >>> #define and #include, as well as functions' declarations, etc.; >> >> A well-designed header contains *only* the following: >> >> 1) inclusion guards; >> 2) macro definitions (#defines); >> 3) type definitions (typedefs); >> 4) function prototypes; >> 5) comments; >> 6) #include directives *ONLY* for those headers that are required for >> the immediate purposes of the header itself. >> >> For example, here's a quick header I threw together a year or so ago: >> >> /* CISPRNG - Cryptographically In-Secure >> * Pseudo-Random Number Generator >> * >> * Written by Richard Heathfield, >> * 20 October 2015. >> * >> * You will also need cisprng.c and a >> * C compiler. >> * >> * The author places this code into the >> * public domain, and so it may be freely >> * used for any legal purpose, although >> * I would recommend against using it >> * in circumstances where you really need >> * a cryptographically secure PRNG, because >> * it isn't one. >> */ >> #ifndef H_CISPRNG_H_ >> #define H_CISPRNG_H_ >> >> #define CISPRNG_RAND_MAX (0x7FFFFFFFUL) >> >> /* Single state versions */ >> /* set the seed */ >> void cisprng_set(unsigned long seed); >> /* get a PRN */ >> unsigned long cisprng_random(void); >> /* get a PRN in a range */ >> unsigned long cisprng_range(unsigned long low, >> unsigned long high); >> /* Custom state versions */ >> unsigned long cisprng_csrandom(unsigned long *pseed); >> unsigned long cisprng_csrange(unsigned long *pseed, >> unsigned long low, >> unsigned long high); >> #endif >> /* end of cisprng.h */ >> >> Note that it doesn't define any types. But if it did, they would go >> after the #defines but before the function prototypes. Nor does it >> include any headers. But *if* I'd used, say, size_t *in the header*, I'd >> have included <stddef.h> in the header. But I would *not* include >> <stddef.h> in the header just because the corresponding C file used >> size_t (which, actually, it doesn't). A module header is not a place to >> hide #includes. >> > > I hope I am not going to cause too much confusion to a learner here, but > I have a few comments about your rules for headers. It may be that you > agree with me, and just did not write your complete rule set. I think we might be able to save Alla some confusion here by suggesting that she avert her eyes. :-) > I think it is important to emphasis that you should only have macros, > types, function prototypes, etc., in a header if these declarations will > be used by other modules. Yes, but. With me so far? :-) I was going to dig out a quotation from King Lear about not taking things far enough, but it turned out not to be quite so apt as I'd hoped. Oh well. Module, right? Well, we have to say what we mean by "module". We might reasonably define it as a source and its associated header, in which case I think your point is fine. But we might also define it as a set of related functions, which might be spread over several sources. If we define it that way (and, frankly, I do), then it becomes reasonable to think of a module as having two headers: one public, and one private. The private header is shared across all the sources that go to make up that module, and the public header is shared across other modules. So, for example, we might have an abstract data type that is defined in mylittlemoduleinternal.h and shared across mylittlemoduleA.c, mylittlemoduleB.c, and mylittlemoduleC.c. And then we have a bunch of prototypes listed in mylittlemodule.h, for sharing with other modules. Would you agree with that? > Anything that is used only within the > implementation C file, should be in that file alone - and not the > header. So if you have a function "cisprng_calculate" that is not > exported, it should not be declared in the header file, and it should be > declared "static" in the C file. But if it is needed by other sources within the same module, that gives us a problem. One possible solution is to share a function pointer in the private header --- but it's messy. > Regarding macros, I would always limit the use of macros to when you > actually need them to be macros. If usage of CISPRNG_RAND_MAX permits, > I would prefer: > > static const unsigned long int cisprng_rand_max = 0x7ffffffful; Yeah, but this is C90, and it's an array size. :-) Okay, obviously it isn't. But I'm sure you take my point. That one could indeed have been a const, but that isn't always possible. > The rules of "const" objects in C mean that you often /do/ need to make > such things #define'd values rather than static consts. Yes. > Assuming you are using C99 or C11 rather than C90 (I know some people > still use C90), You hear that, folks? David thinks I'm *some people*! Fame at last! > then "static inline" functions are often a better > alternative to function-like macros, and can go in headers as well. > > I would also put more emphasis on the comments. Ideally, the comments > in a header should tell the reader all they need to know about the > functions and how to use them. Up to a point, Lord Copper. > It makes it easier for people using the > code - they don't have to look elsewhere for documentation. Of course, > there are limits - comments should not be so extensive that it is hard > to see the code! And that's why we have external docs. -- 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
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-12-15 23:20 +0100 |
| Message-ID | <o2v4s3$hpv$1@dont-email.me> |
| In reply to | #99508 |
On 15/12/16 16:37, Richard Heathfield wrote: > On 15/12/16 15:14, David Brown wrote: >> On 15/12/16 15:12, Richard Heathfield wrote: >>> [the code] >>> >>> On 15/12/16 13:05, Alla _ wrote: >>> >>>> (3) I will use a header file, in which I will store preprocessor >>>> commands, like >>>> #define and #include, as well as functions' declarations, etc.; >>> >>> A well-designed header contains *only* the following: >>> >>> 1) inclusion guards; >>> 2) macro definitions (#defines); >>> 3) type definitions (typedefs); >>> 4) function prototypes; >>> 5) comments; >>> 6) #include directives *ONLY* for those headers that are required for >>> the immediate purposes of the header itself. >>> >>> For example, here's a quick header I threw together a year or so ago: >>> >>> /* CISPRNG - Cryptographically In-Secure >>> * Pseudo-Random Number Generator >>> * >>> * Written by Richard Heathfield, >>> * 20 October 2015. >>> * >>> * You will also need cisprng.c and a >>> * C compiler. >>> * >>> * The author places this code into the >>> * public domain, and so it may be freely >>> * used for any legal purpose, although >>> * I would recommend against using it >>> * in circumstances where you really need >>> * a cryptographically secure PRNG, because >>> * it isn't one. >>> */ >>> #ifndef H_CISPRNG_H_ >>> #define H_CISPRNG_H_ >>> >>> #define CISPRNG_RAND_MAX (0x7FFFFFFFUL) >>> >>> /* Single state versions */ >>> /* set the seed */ >>> void cisprng_set(unsigned long seed); >>> /* get a PRN */ >>> unsigned long cisprng_random(void); >>> /* get a PRN in a range */ >>> unsigned long cisprng_range(unsigned long low, >>> unsigned long high); >>> /* Custom state versions */ >>> unsigned long cisprng_csrandom(unsigned long *pseed); >>> unsigned long cisprng_csrange(unsigned long *pseed, >>> unsigned long low, >>> unsigned long high); >>> #endif >>> /* end of cisprng.h */ >>> >>> Note that it doesn't define any types. But if it did, they would go >>> after the #defines but before the function prototypes. Nor does it >>> include any headers. But *if* I'd used, say, size_t *in the header*, I'd >>> have included <stddef.h> in the header. But I would *not* include >>> <stddef.h> in the header just because the corresponding C file used >>> size_t (which, actually, it doesn't). A module header is not a place to >>> hide #includes. >>> >> >> I hope I am not going to cause too much confusion to a learner here, but >> I have a few comments about your rules for headers. It may be that you >> agree with me, and just did not write your complete rule set. > > I think we might be able to save Alla some confusion here by suggesting > that she avert her eyes. :-) > >> I think it is important to emphasis that you should only have macros, >> types, function prototypes, etc., in a header if these declarations will >> be used by other modules. > > Yes, but. > > With me so far? :-) Yes... > > I was going to dig out a quotation from King Lear about not taking > things far enough, but it turned out not to be quite so apt as I'd > hoped. Oh well. > > Module, right? Well, we have to say what we mean by "module". We might > reasonably define it as a source and its associated header, in which > case I think your point is fine. Yes, that is what I was meaning by "module". Of course you are correct that I should have defined it - especially as it could mean other things. > But we might also define it as a set of > related functions, which might be spread over several sources. If we > define it that way (and, frankly, I do), then it becomes reasonable to > think of a module as having two headers: one public, and one private. > The private header is shared across all the sources that go to make up > that module, and the public header is shared across other modules. Agreed. If you prefer to call this sort of multi-file "lump" a "module", what do you call a header/C file "lump" ? It is a real shame that C has no good way of dealing with this sort of thing properly - no namespaces, and only two levels of identifier visibility (static to a compilation unit, or global for the whole program). > > So, for example, we might have an abstract data type that is defined in > mylittlemoduleinternal.h and shared across mylittlemoduleA.c, > mylittlemoduleB.c, and mylittlemoduleC.c. And then we have a bunch of > prototypes listed in mylittlemodule.h, for sharing with other modules. > > Would you agree with that? Yes, that seems reasonable. It is not exactly how I would organise it, but close enough for now. > >> Anything that is used only within the >> implementation C file, should be in that file alone - and not the >> header. So if you have a function "cisprng_calculate" that is not >> exported, it should not be declared in the header file, and it should be >> declared "static" in the C file. > > But if it is needed by other sources within the same module, that gives > us a problem. One possible solution is to share a function pointer in > the private header --- but it's messy. Yes. In this particular case, the program is small enough that such multi-file modules are not going to be necessary, so a simpler system is possible. But the simpler system does not scale to a more hierarchical organisation without changes such as you suggest. > >> Regarding macros, I would always limit the use of macros to when you >> actually need them to be macros. If usage of CISPRNG_RAND_MAX permits, >> I would prefer: >> >> static const unsigned long int cisprng_rand_max = 0x7ffffffful; > > Yeah, but this is C90, and it's an array size. :-) > > Okay, obviously it isn't. But I'm sure you take my point. That one could > indeed have been a const, but that isn't always possible. > As I note below. In some circumstances you can use a enum constant instead of a #define'd constant when a "static const" won't work - but I find that to be rather artificial unless it is part of a collection of constants for which an enum makes sense. >> The rules of "const" objects in C mean that you often /do/ need to make >> such things #define'd values rather than static consts. > > Yes. > >> Assuming you are using C99 or C11 rather than C90 (I know some people >> still use C90), > > You hear that, folks? David thinks I'm *some people*! Fame at last! I am sure you have good reasons for using C90. But I think it usually makes sense for someone relatively new to C to use C99 features when they make coding clearer (following Heathfield's rule, naturally) - C99 is the current dominant C standard used, I believe. (And C11 doesn't add much that I find useful - at least not beyond the gcc extensions I have used for years. Static assertions are great, but you could do them with an ugly macro in C90 and C99.) > >> then "static inline" functions are often a better >> alternative to function-like macros, and can go in headers as well. >> >> I would also put more emphasis on the comments. Ideally, the comments >> in a header should tell the reader all they need to know about the >> functions and how to use them. > > Up to a point, Lord Copper. > >> It makes it easier for people using the >> code - they don't have to look elsewhere for documentation. Of course, >> there are limits - comments should not be so extensive that it is hard >> to see the code! > > And that's why we have external docs. > If the usage documentation can be written in the header (without passing "the point"), then that is a good thing. External documentation can go into more detail, examples, etc., but there is always the risk of getting out of synchronisation between the code and the document or simply not having the document at hand when you are working with the code. Documentation in the header file is /always/ quickly at hand when you are working with the code!
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-15 23:27 +0000 |
| Message-ID | <o2v8qp$1vo$1@dont-email.me> |
| In reply to | #99577 |
On 15/12/16 22:20, David Brown wrote: > On 15/12/16 16:37, Richard Heathfield wrote: <snip> >> Module, right? Well, we have to say what we mean by "module". We might >> reasonably define it as a source and its associated header, in which >> case I think your point is fine. > > Yes, that is what I was meaning by "module". Of course you are correct > that I should have defined it - especially as it could mean other things. > >> But we might also define it as a set of >> related functions, which might be spread over several sources. If we >> define it that way (and, frankly, I do), then it becomes reasonable to >> think of a module as having two headers: one public, and one private. >> The private header is shared across all the sources that go to make up >> that module, and the public header is shared across other modules. > > Agreed. > > If you prefer to call this sort of multi-file "lump" a "module", what do > you call a header/C file "lump" ? A lump. What else? The correct term is "preprocessing translation unit". PTU, anyone? But I tend to eschew the P and stick to "translation unit" (which is actually the correct term for what remains after preprocessing, but I'm not too fussed about the difference except when arguing about the difference!). > It is a real shame that C has no good way of dealing with this sort of > thing properly - no namespaces, and only two levels of identifier > visibility (static to a compilation unit, or global for the whole program). Yes. I'd like to see an hierarchy of visibility. But it isn't going to happen, and I can live with that. >> So, for example, we might have an abstract data type that is defined in >> mylittlemoduleinternal.h and shared across mylittlemoduleA.c, >> mylittlemoduleB.c, and mylittlemoduleC.c. And then we have a bunch of >> prototypes listed in mylittlemodule.h, for sharing with other modules. >> >> Would you agree with that? > > Yes, that seems reasonable. It is not exactly how I would organise it, > but close enough for now. I think that's important, actually. What I mean is, okay, you and I would tend to choose to organise stuff in different ways, but those differences are likely to be fairly minor, and each of us would recognise that the other has made reasonable choices that just happen to be different to our own reasonable choice. This is what cultural diversity is all about! >>> Anything that is used only within the >>> implementation C file, should be in that file alone - and not the >>> header. So if you have a function "cisprng_calculate" that is not >>> exported, it should not be declared in the header file, and it should be >>> declared "static" in the C file. >> >> But if it is needed by other sources within the same module, that gives >> us a problem. One possible solution is to share a function pointer in >> the private header --- but it's messy. > > Yes. Yeeesss. It's... it isn't just messy, is it? It's actually icky. There is no /good/ solution, as far as I know. What I actually do in this situation (when I get to choose, anyway) is to declare the function in the private header, and make it extern (not explicitly, but by not making it static), and then just not telling the user-programmer it's there! That way, even though they can in theory call it, first they have to find out about it, and they can only do that by going to some serious and deliberate investigative effort. > In this particular case, the program is small enough that such > multi-file modules are not going to be necessary, so a simpler system is > possible. But the simpler system does not scale to a more hierarchical > organisation without changes such as you suggest. Namespaces would be pleasant, wouldn't they? But we're not going to get them, and that's that. >>> Assuming you are using C99 or C11 rather than C90 (I know some people >>> still use C90), >> >> You hear that, folks? David thinks I'm *some people*! Fame at last! > > I am sure you have good reasons for using C90. But I think it usually > makes sense for someone relatively new to C to use C99 features when > they make coding clearer (following Heathfield's rule, naturally) My blushes, Watson! My reasons for using C90 are as follows: 1) it works everywhere; 2) C99 doesn't add anything I need that I can't get from C++. So, if I need those features, I'll just write that code in C++ instead, which means I get lots of toys to play with. > If the usage documentation can be written in the header (without passing > "the point"), then that is a good thing. A brief summary, yes. > External documentation can go > into more detail, examples, etc., but there is always the risk of > getting out of synchronisation between the code and the document But that's true of the internal documentation as well --- it can and does get out of synch with the code. The solution to synchronisation problems is discipline, and that's required whether the documentation is internal or external. > or > simply not having the document at hand when you are working with the > code. Documentation in the header file is /always/ quickly at hand when > you are working with the code! As long as you know the code well enough to know where to look, or know what you're looking for well enough to execute a grep. External docs can cover several headers in one indexed document. They can offer hyperlinks to specific function descriptions, they can contain diagrams (and I don't mean ASCII art), and they can use all the tricks of the word processing trade to make the document more readable than can generally be managed in eighty columns of Courier 12. -- 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
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-12-16 12:10 +0100 |
| Message-ID | <o30i0a$58m$1@dont-email.me> |
| In reply to | #99582 |
On 16/12/16 00:27, Richard Heathfield wrote: > On 15/12/16 22:20, David Brown wrote: >> On 15/12/16 16:37, Richard Heathfield wrote: > > <snip> > >>> Module, right? Well, we have to say what we mean by "module". We might >>> reasonably define it as a source and its associated header, in which >>> case I think your point is fine. >> >> Yes, that is what I was meaning by "module". Of course you are correct >> that I should have defined it - especially as it could mean other things. >> >>> But we might also define it as a set of >>> related functions, which might be spread over several sources. If we >>> define it that way (and, frankly, I do), then it becomes reasonable to >>> think of a module as having two headers: one public, and one private. >>> The private header is shared across all the sources that go to make up >>> that module, and the public header is shared across other modules. >> >> Agreed. >> >> If you prefer to call this sort of multi-file "lump" a "module", what do >> you call a header/C file "lump" ? > > A lump. What else? > > The correct term is "preprocessing translation unit". PTU, anyone? But I > tend to eschew the P and stick to "translation unit" (which is actually > the correct term for what remains after preprocessing, but I'm not too > fussed about the difference except when arguing about the difference!). No, a translation unit (or compilation unit) is something different. If you have: widget.h // Declarations for widget functions widget.c // Implementation of widget functions game.c // Uses widget functions Then widget.c + any files it #include's (hopefully including widget.h) is a translation unit. So is game.c + any files /it/ includes (including widget.h). I am wondering what you call the lump "widget.h + widget.c", if anything? Maybe it is just a "module" that happens to contain only two files. > >> It is a real shame that C has no good way of dealing with this sort of >> thing properly - no namespaces, and only two levels of identifier >> visibility (static to a compilation unit, or global for the whole >> program). > > Yes. I'd like to see an hierarchy of visibility. But it isn't going to > happen, and I can live with that. If you couldn't live with it, you wouldn't be here - you'd be next door in c.l.c++ :-) > >>> So, for example, we might have an abstract data type that is defined in >>> mylittlemoduleinternal.h and shared across mylittlemoduleA.c, >>> mylittlemoduleB.c, and mylittlemoduleC.c. And then we have a bunch of >>> prototypes listed in mylittlemodule.h, for sharing with other modules. >>> >>> Would you agree with that? >> >> Yes, that seems reasonable. It is not exactly how I would organise it, >> but close enough for now. > > I think that's important, actually. What I mean is, okay, you and I > would tend to choose to organise stuff in different ways, but those > differences are likely to be fairly minor, and each of us would > recognise that the other has made reasonable choices that just happen to > be different to our own reasonable choice. This is what cultural > diversity is all about! Yes. Since C does not have support for "modules", "units", "namespaces", "lumps", etc., beyond the humble #include mechanism, we have the freedom to implement whatever balance of predictable rules and flexibility suits the job at hand. > >>>> Anything that is used only within the >>>> implementation C file, should be in that file alone - and not the >>>> header. So if you have a function "cisprng_calculate" that is not >>>> exported, it should not be declared in the header file, and it >>>> should be >>>> declared "static" in the C file. >>> >>> But if it is needed by other sources within the same module, that gives >>> us a problem. One possible solution is to share a function pointer in >>> the private header --- but it's messy. >> >> Yes. > > Yeeesss. It's... it isn't just messy, is it? It's actually icky. There > is no /good/ solution, as far as I know. > > What I actually do in this situation (when I get to choose, anyway) is > to declare the function in the private header, and make it extern (not > explicitly, but by not making it static), and then just not telling the > user-programmer it's there! That way, even though they can in theory > call it, first they have to find out about it, and they can only do that > by going to some serious and deliberate investigative effort. That would work. I use "extern" explicitly on function declarations in headers (except for "static inline" functions, of course). I know it is unnecessary, but I feel that it should have been necessary - "extern by default" is a design mistake in C, IMHO. It also makes it more consistent with extern variable declarations. (In small embedded systems, it is often useful to have "global variables". The balance of tradeoffs is different than on bigger systems.) > >> In this particular case, the program is small enough that such >> multi-file modules are not going to be necessary, so a simpler system is >> possible. But the simpler system does not scale to a more hierarchical >> organisation without changes such as you suggest. > > Namespaces would be pleasant, wouldn't they? But we're not going to get > them, and that's that. Indeed. > >>>> Assuming you are using C99 or C11 rather than C90 (I know some people >>>> still use C90), >>> >>> You hear that, folks? David thinks I'm *some people*! Fame at last! >> >> I am sure you have good reasons for using C90. But I think it usually >> makes sense for someone relatively new to C to use C99 features when >> they make coding clearer (following Heathfield's rule, naturally) > > My blushes, Watson! > > My reasons for using C90 are as follows: > > 1) it works everywhere; > 2) C99 doesn't add anything I need that I can't get from C++. So, if I > need those features, I'll just write that code in C++ instead, which > means I get lots of toys to play with. My reasons for using C99 are: 1) It works everywhere I need it to work. 2) It adds a lot of useful things to C without needing to go for C++. I am seeing more interest in C++ in the sorts of systems I work with - the combination of better compilers, useful features in C++11/C++14, and more powerful microcontrollers at the small end mean that C++ is feasible on projects where previously C was the only option. But since I can use C99, I don't have quite the same pressure to move to C++ as C90 programmers do :-) > >> If the usage documentation can be written in the header (without passing >> "the point"), then that is a good thing. > > A brief summary, yes. > >> External documentation can go >> into more detail, examples, etc., but there is always the risk of >> getting out of synchronisation between the code and the document > > But that's true of the internal documentation as well --- it can and > does get out of synch with the code. The solution to synchronisation > problems is discipline, and that's required whether the documentation is > internal or external. Also true. It is easier, however, to keep your internal documentation in sync - you've got the file open and have made changes to the code in it, so you can change the lines of text there too. Your external documentation might mean different tools, different procedures, etc. - and it takes more discipline to get right. The best is to write self-documenting code - then it is never out of sync. At least, don't write anything in comments that could be expressed in code (such as by good choice of function and parameter names). > >> or >> simply not having the document at hand when you are working with the >> code. Documentation in the header file is /always/ quickly at hand when >> you are working with the code! > > As long as you know the code well enough to know where to look, or know > what you're looking for well enough to execute a grep. External docs can > cover several headers in one indexed document. They can offer hyperlinks > to specific function descriptions, they can contain diagrams (and I > don't mean ASCII art), and they can use all the tricks of the word > processing trade to make the document more readable than can generally > be managed in eighty columns of Courier 12. > Some of use have moved to using more capable IDE's for their development work... Of course you are correct that external documentation can have more features and flexibility than internal documentation in comments. It is also possible to make combinations of the two. On one customer project I made extensive use of doxygen. So each item in the headers had doxygen comments, and there were comment blocks giving a bit more general information about the modules (or "lumps"). For larger sections of documentation, including diagrams, I used separate text files that were contained within the source code tree and processed by doxygen, but without any code (except examples and the like).
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-16 11:43 +0000 |
| Message-ID | <o30jtg$bhm$1@dont-email.me> |
| In reply to | #99632 |
On 16/12/16 11:10, David Brown wrote: > On 16/12/16 00:27, Richard Heathfield wrote: >> On 15/12/16 22:20, David Brown wrote: >>> On 15/12/16 16:37, Richard Heathfield wrote: >> >> <snip> >> >>>> Module, right? Well, we have to say what we mean by "module". We might >>>> reasonably define it as a source and its associated header, in which >>>> case I think your point is fine. >>> >>> Yes, that is what I was meaning by "module". Of course you are correct >>> that I should have defined it - especially as it could mean other things. >>> >>>> But we might also define it as a set of >>>> related functions, which might be spread over several sources. If we >>>> define it that way (and, frankly, I do), then it becomes reasonable to >>>> think of a module as having two headers: one public, and one private. >>>> The private header is shared across all the sources that go to make up >>>> that module, and the public header is shared across other modules. >>> >>> Agreed. >>> >>> If you prefer to call this sort of multi-file "lump" a "module", what do >>> you call a header/C file "lump" ? >> >> A lump. What else? >> >> The correct term is "preprocessing translation unit". PTU, anyone? But I >> tend to eschew the P and stick to "translation unit" (which is actually >> the correct term for what remains after preprocessing, but I'm not too >> fussed about the difference except when arguing about the difference!). > > No, a translation unit (or compilation unit) is something different. Er, no it isn't. > If you have: > > widget.h // Declarations for widget functions > widget.c // Implementation of widget functions > game.c // Uses widget functions > > Then widget.c + any files it #include's (hopefully including widget.h) > is a translation unit. Yep. Dat what I said. > So is game.c + any files /it/ includes > (including widget.h). Dat what I said, too. > I am wondering what you call the lump "widget.h + widget.c", if > anything? Oh, you mean sans otherwidget.h and stdio.h and so on? Uh, I don't have a name for that. I don't /need/ a name for that. > Maybe it is just a "module" that happens to contain only two > files. Oh, sure. Sorry, was that not clear? It's amazing how tangled these discussions can be come when we don't spell everything out. Yes, I am perfectly content to have a module consisting of just one C file and its header. But I am /also/ perfectly content for the module to have more than one C file. I'm not terribly interested in linkers so I don't know whether this has changed, but they didn't used to be terribly bright, and they couldn't pull in just one function from an object file even if only one were used; they had to pull in the whole file. So, when space was so terribly important (and no doubt it still is for many people), C programmers would sometimes put each function in its own source file, even if there was a clear relationship existing amongst a bunch of those functions. In those circumstances, to call each one a module when, actually, it was the whole bunch of them that was really the module, would have seemed a bit silly. <snip> > The best is to write self-documenting code - then it is never out of > sync. At least, don't write anything in comments that could be > expressed in code (such as by good choice of function and parameter names). Yes. >>> or >>> simply not having the document at hand when you are working with the >>> code. Documentation in the header file is /always/ quickly at hand when >>> you are working with the code! >> >> As long as you know the code well enough to know where to look, or know >> what you're looking for well enough to execute a grep. External docs can >> cover several headers in one indexed document. They can offer hyperlinks >> to specific function descriptions, they can contain diagrams (and I >> don't mean ASCII art), and they can use all the tricks of the word >> processing trade to make the document more readable than can generally >> be managed in eighty columns of Courier 12. >> > > Some of use have moved to using more capable IDE's for their development > work... You have an IDE that's more capable than Linux? I'm impressed! -- 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
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-12-16 14:01 +0100 |
| Message-ID | <o30ohi$rcr$1@dont-email.me> |
| In reply to | #99639 |
On 16/12/16 12:43, Richard Heathfield wrote: > On 16/12/16 11:10, David Brown wrote: >> On 16/12/16 00:27, Richard Heathfield wrote: >>> On 15/12/16 22:20, David Brown wrote: >>>> On 15/12/16 16:37, Richard Heathfield wrote: >>> <snip> > > Oh, sure. Sorry, was that not clear? It's amazing how tangled these > discussions can be come when we don't spell everything out. Yes, I am > perfectly content to have a module consisting of just one C file and its > header. But I am /also/ perfectly content for the module to have more > than one C file. It is untangled now, I think. > > I'm not terribly interested in linkers so I don't know whether this has > changed, but they didn't used to be terribly bright, and they couldn't > pull in just one function from an object file even if only one were > used; they had to pull in the whole file. So, when space was so terribly > important (and no doubt it still is for many people), C programmers > would sometimes put each function in its own source file, even if there > was a clear relationship existing amongst a bunch of those functions. In > those circumstances, to call each one a module when, actually, it was > the whole bunch of them that was really the module, would have seemed a > bit silly. Linkers are a bit brighter now, especially along with smarter compilers. A common usage (in embedded systems, where space often is tight) is to use "function sections" in the compiler so that each function is put into its own little code section. On the linker, you enable "garbage collection" (a poor choice of name for the feature, I think) which collects all the code sections which are reachable from critical code such as main(), the reset handler, interrupt functions, etc. Sections are joined up as graphs, and anything left on its own island disconnected from the main()land get thrown out. Even smarter linkers work with the compiler for link-time optimisation, but that's another story. For my own coding, I can usually put all the related files into a single C file - so two-file modules are the norm for me. But then, I don't often have functions defined that are not going to be part of the final program - and if I do, "function sections" keep the output tidy. > > <snip> > >> The best is to write self-documenting code - then it is never out of >> sync. At least, don't write anything in comments that could be >> expressed in code (such as by good choice of function and parameter >> names). > > Yes. > >>>> or >>>> simply not having the document at hand when you are working with the >>>> code. Documentation in the header file is /always/ quickly at hand >>>> when >>>> you are working with the code! >>> >>> As long as you know the code well enough to know where to look, or know >>> what you're looking for well enough to execute a grep. External docs can >>> cover several headers in one indexed document. They can offer hyperlinks >>> to specific function descriptions, they can contain diagrams (and I >>> don't mean ASCII art), and they can use all the tricks of the word >>> processing trade to make the document more readable than can generally >>> be managed in eighty columns of Courier 12. >>> >> >> Some of use have moved to using more capable IDE's for their development >> work... > > You have an IDE that's more capable than Linux? I'm impressed! > I have an IDE that can display more than eighty columns, open several files at once, and even choose different fonts (it won't let me pick Courier 12, however). Of course, those big files and long lines are a pain when you need to fix things via a mobile telephone, JuiceSSH, and nano editor - but fortunately I haven't had to do that very often.
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2016-12-16 13:12 +0000 |
| Message-ID | <o30p5p$tg2$1@dont-email.me> |
| In reply to | #99645 |
On 16/12/16 13:01, David Brown wrote: > On 16/12/16 12:43, Richard Heathfield wrote: >> On 16/12/16 11:10, David Brown wrote: >>> On 16/12/16 00:27, Richard Heathfield wrote: <snip> >>>> As long as you know the code well enough to know where to look, or know >>>> what you're looking for well enough to execute a grep. External docs can >>>> cover several headers in one indexed document. They can offer hyperlinks >>>> to specific function descriptions, they can contain diagrams (and I >>>> don't mean ASCII art), and they can use all the tricks of the word >>>> processing trade to make the document more readable than can generally >>>> be managed in eighty columns of Courier 12. >>>> >>> >>> Some of use have moved to using more capable IDE's for their development >>> work... >> >> You have an IDE that's more capable than Linux? I'm impressed! >> > > I have an IDE that can display more than eighty columns, open several > files at once, and even choose different fonts (it won't let me pick > Courier 12, however). Well, of course I do too, but I /choose/ to keep my code display quite traditional because I find it easier to work that way. Does your text editor allow you to put hyperlinks in the code without changing the code itself? If so, I'm impressed. And can your text editor also display pixel-perfect (i.e. not just ASCII art) diagrams? If so, I'm even more impressed. > Of course, those big files and long lines are a pain when you need to > fix things via a mobile telephone, JuiceSSH, and nano editor - but > fortunately I haven't had to do that very often. That's what cars (and trains and boats and planes) are for. -- 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
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-12-16 14:57 +0100 |
| Message-ID | <o30rq6$77o$1@dont-email.me> |
| In reply to | #99647 |
On 16/12/16 14:12, Richard Heathfield wrote: > On 16/12/16 13:01, David Brown wrote: >> On 16/12/16 12:43, Richard Heathfield wrote: >>> On 16/12/16 11:10, David Brown wrote: >>>> On 16/12/16 00:27, Richard Heathfield wrote: > > <snip> > >>>>> As long as you know the code well enough to know where to look, or >>>>> know >>>>> what you're looking for well enough to execute a grep. External >>>>> docs can >>>>> cover several headers in one indexed document. They can offer >>>>> hyperlinks >>>>> to specific function descriptions, they can contain diagrams (and I >>>>> don't mean ASCII art), and they can use all the tricks of the word >>>>> processing trade to make the document more readable than can generally >>>>> be managed in eighty columns of Courier 12. >>>>> >>>> >>>> Some of use have moved to using more capable IDE's for their >>>> development >>>> work... >>> >>> You have an IDE that's more capable than Linux? I'm impressed! >>> >> >> I have an IDE that can display more than eighty columns, open several >> files at once, and even choose different fonts (it won't let me pick >> Courier 12, however). > > Well, of course I do too, but I /choose/ to keep my code display quite > traditional because I find it easier to work that way. Does your text > editor allow you to put hyperlinks in the code without changing the code > itself? If so, I'm impressed. And can your text editor also display > pixel-perfect (i.e. not just ASCII art) diagrams? If so, I'm even more > impressed. > I think we have had one of those tangles again... I meant that my IDE (Eclipse) can make files more readable than you get with 80 columns Courier 12, not that it can do everything you would want from a full documentation system. (To be a smart-ass - yes, I can put hyperlinks in the code without changing the code itself. I just type them in comments. But they are not clickable links, which I suspect is what you meant.) I am sure there are editors that /can/ show pictures and hyperlinks - especially those geared more towards web development than C coding. And Eclipse can show all sorts of graphics stuff too - I only use a tiny fraction of its features. >> Of course, those big files and long lines are a pain when you need to >> fix things via a mobile telephone, JuiceSSH, and nano editor - but >> fortunately I haven't had to do that very often. > > That's what cars (and trains and boats and planes) are for. >
[toc] | [prev] | [next] | [standalone]
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
Back to top | Article view | comp.lang.c
csiph-web