Slackware This Forum is for the discussion of Slackware Linux.
|
Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
|
11-29-2013, 01:43 AM
|
#16
|
Member
Registered: Oct 2011
Location: Texas, USA
Distribution: LFS-SVN, Gentoo~amd64, CentOS-7, Slackware64-current, FreeBSD-11.1, Arch
Posts: 229
Rep: 
|
Quote:
Originally Posted by aaditya
Ah, I understand. I will use it (-ansi -pedantic) now onwards 
|
Now if you really want to get a full measure of the GCC diagnostics, here's a recommended set of flags to turn up the warnings full blast. This is what I use in production code:
Code:
gcc -ansi -pedantic -Wall -Wextra -Wconversion -Wstrict-overflow -Wformat=2
I well recall when first allowed the compiler to nitpick my code many, many, many years ago. It was a humbling experience since I had been getting away with a lot of questionable things for a long time. I buckled down and took the attitude that the compiler was trying to help me and then cleaned up a lot of junk in my code. Nowadays, even the simplest toy program that I write has to pass that gauntlet of GCC (or clang) warnings.
Obviously logic errors aren't detected but much that is potentially suspect is caught by letting the compiler point out deficiencies at the source code level.
|
|
1 members found this post helpful.
|
11-29-2013, 02:17 AM
|
#17
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by re_nelson
Now if you really want to get a full measure of the GCC diagnostics, here's a recommended set of flags to turn up the warnings full blast. This is what I use in production code:
Code:
gcc -ansi -pedantic -Wall -Wextra -Wconversion -Wstrict-overflow -Wformat=2
I well recall when first allowed the compiler to nitpick my code many, many, many years ago. It was a humbling experience since I had been getting away with a lot of questionable things for a long time. I buckled down and took the attitude that the compiler was trying to help me and then cleaned up a lot of junk in my code. Nowadays, even the simplest toy program that I write has to pass that gauntlet of GCC (or clang) warnings.
Obviously logic errors aren't detected but much that is potentially suspect is caught by letting the compiler point out deficiencies at the source code level.
|
Ah, sorry, I meant that I would use int main() instead of void main()
Using just the -ansi -pedantic options that you earlier described, I seemed to get a lot of warnings, and even more when using all the flags you mentioned!
I have attached the error pastes, I will have a look at them as I can
errors
errors-all
diff-between-flags
|
|
|
11-29-2013, 02:34 AM
|
#18
|
Member
Registered: Oct 2011
Location: Texas, USA
Distribution: LFS-SVN, Gentoo~amd64, CentOS-7, Slackware64-current, FreeBSD-11.1, Arch
Posts: 229
Rep: 
|
Quote:
Originally Posted by aaditya
Using just the -ansi -pedantic options that you earlier described, I seemed to get a lot of warnings, and even more when using all the flags you mentioned!
I have attached the error pastes, I will have a look at them as I can
errors
errors-all
diff-between-flags
|
We're probably in grave danger of a bad case of topic drift since this isn't Slackware-specific (although Slackware is an excellent platform for learning C since all of the tools and libraries are all there out of the box). So, I'll wrap up my participation in this thread by hoping you have fun tracking down all of the nitpicky compiler warnings.
Although it's initially quite a chore, it will pay off because your code will be clean and solid. Although it may not seem that way at this point, the compiler is your friend!  Yes, an annoying, pedantic friend but still a friend.
|
|
|
11-29-2013, 02:39 AM
|
#19
|
Member
Registered: Sep 2011
Posts: 925
|
Quote:
Originally Posted by re_nelson
It's a violation of the C standard to use the void main() signature. The fact that it "works" on most implementations is not relevant in terms of standard conformance. It comes at no cost and is the right thing to do.
|
If the function signature between caller and callee differs, you simply get undefined behavior (means unreliable programs just working by accident, like systemd). The reason why a C compiler doesn't complain is because of its default assumption that the programmer knows what he's doing.
There are (embedded) implementations using void main() and there void main() is the (only) correct thing.
But our the standard C library does a call to a main() function returning an int, because int is the default return type of C. You may get away with it, if your caller isn't using the return value, but the C library actually is using the return value of main() to call _exit() with it. (So calling exit() yourself is just a waste of time, returning from main() is just fine).
|
|
1 members found this post helpful.
|
11-29-2013, 03:16 AM
|
#20
|
Member
Registered: Sep 2011
Posts: 925
|
Some notes on the code:
Quote:
Code:
//Extract the year,month,day components from the date
char yi[5],yf[5],mi[3],mf[3],di[3],df[3]; //size+1 for null character at the end
strncpy (yi, argv[1], 4);
strncpy (mi, argv[1]+5, 2);
strncpy (di, argv[1]+8, 3);
strncpy (yf, argv[2], 4);
strncpy (mf, argv[2]+5, 2);
strncpy (df, argv[2]+8, 3);
yi[4]='\0'; //insert null character at the end
mi[2]='\0';
yf[4]='\0'; //insert null character at the end
mf[2]='\0';
|
Learning to do string handling correct in C is very hard. Seeing someone calling strcpy/strncpy() numerous times is a sure sign, that something is done wrong.
What is argv[1]+5 actually doing? Well, it's reading beyond the end of the string from invalid memory, if I just call your program with "dur 0 0" for example.
So what can you do to learn who to do C string handling right?
Remove the #include <string.h> and implement the thing without using any string functions from the C library. It's possible. Learn how to work with char arrays and string pointers first, how stop at the end of the string and how to validate the input to your program. Use the string library later, when you know exactly, what's going on.
Don't declare functions inside header files (to_int.h) and don't use the GPLv3 preamble on trivial functions like to_int(), they don't reach the threshold of originality for receiving copyright anyway. Beside that, atoi() from the C standard library is doing exactly the same thing. Writing good C programs without knowing the standard library is not possible...
One the final question: What exactly has this thread to do with Slackware at all?
|
|
1 members found this post helpful.
|
11-29-2013, 03:53 AM
|
#21
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by jtsn
Some notes on the code:
Learning to do string handling correct in C is very hard. Seeing someone calling strcpy/strncpy() numerous times is a sure sign, that something is done wrong.
What is argv[1]+5 actually doing? Well, it's reading beyond the end of the string from invalid memory, if I just call your program with "dur 0 0" for example.
So what can you do to learn who to do C string handling right?
Remove the #include <string.h> and implement the thing without using any string functions from the C library. It's possible. Learn how to work with char arrays and string pointers first, how stop at the end of the string and how to validate the input to your program. Use the string library later, when you know exactly, what's going on.
Don't declare functions inside header files (to_int.h) and don't use the GPLv3 preamble on trivial functions like to_int(), they don't reach the threshold of originality for receiving copyright anyway. Beside that, atoi() from the C standard library is doing exactly the same thing. Writing good C programs without knowing the standard library is not possible...
One the final question: What exactly has this thread to do with Slackware at all?
|
Ah, sorry I am not very well versed in C.
I had made this program to be called with the correct arguments by an external program, and not by the user, and hence skipped checking for invalid input 
(I also mention this in a comment)
Will try to implement this without the library function <string.h>, perhaps add a function in to_int.h to do this.
Will read more on what header files are and what they contain, and accordingly change to_int.h to to_int.c
I used the GPL because I made this on my own, so I think I can use it  (didnt know about the atoi() function, I will try to acquaint myself with the standard library functions, thx)
I posted this here becasue-
1.I use Slackware and wanted to share it with Slackware users.
2.I think that many Slackware users are programmers, and I thought that if I posted here, maybe some of them will give feedback  (thank you) 
3.I list 2 applications for this program which can be used on Slackware.
Thanks 
Last edited by aaditya; 11-29-2013 at 04:48 AM.
|
|
|
11-29-2013, 08:02 AM
|
#22
|
Senior Member
Registered: Oct 2003
Location: Northeastern Michigan, where Carhartt is a Designer Label
Distribution: Slackware 32- & 64-bit Stable
Posts: 3,541
|
Keep in mind that what julday() is doing is converting a Gregorian calendar date to a fixed "address" in time. Julian Day 0 is -4713-01-01 (BCE), every day since is one "tick" of the Julian Day "clock." Today (2013-11-29) is 2456626, using a different function, caldat():
Code:
julian
2456626
caldat 2456626
Julian Day 2456626: 11/29/2013
The julian program produces today's Julian Day, the caldat program produces the Gregorian calendar date from the Julian Day (it's a check to convert one way then covert the other way to make sure you've got it right). The equations are all given in the Wikipedia article noted above. The piece of the julian program that does the conversion is (using the system clock):
Code:
/* get the system time */
(void) time (&now);
/* make it local time */
tm = localtime (&now);
if (vopt) {
(void) fprintf (stdout,
"%02d%02d.%02d %02d/%02d/%04d %ld\n",
tm->tm_hour, tm->tm_min, tm->tm_sec,
tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
julday (tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900));
} else {
(void) fprintf (stdout, "%ld\n",
julday (tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900));
}
It simply invokes the same julday() function used in ndays.c, which returns the Julian Day, to do so.
The idea of ndays is that you determine the Julian Day for each of two Gregorian calendar dates and evaluate the difference. As it turns out, I'm 25425 days old as of today (ouch!). Actually, ndays is quite useful in project planning; determine what needs to be done, determine how long it takes to do a given task, put it all together and determine when the project will be complete (Gantt charts and the like). If you have somebody's birth date and you need to know their age, pretty simple (divide ndays by 365.25 and you're pretty close).
Here's caldat.c:
Code:
#include <math.h>
#include <time.h>
#define IGREG 2299161
void caldat (time_t julian, int *mm, int *id, int *iyyy)
{
time_t ja, jalpha, jb, jc, jd, je;
if (julian >= IGREG) {
jalpha = ((float) (julian - 1867216) - 0.25) / 36524.25;
ja = julian + 1 + jalpha - (time_t) (0.25 * jalpha);
} else {
ja = julian;
}
jb = ja + 1524;
jc = 6680.0 + ((float) (jb - 2439870) - 122.1) / 365.25;
jd = 365 * jc + (0.25 * jc);
je = (jb - jd) / 30.6001;
*id = jb - jd - (int) (30.6001 * je);
*mm = je - 1;
if (*mm > 12)
*mm -= 12;
*iyyy = jc - 4715;
if (*mm > 2)
--(*iyyy);
if (*iyyy <= 0)
--(*iyyy);
}
#undef IGREG
Again, see the Wikipedia article to help with understanding the calculations.
Anyway, I hope you find this useful.
|
|
|
11-29-2013, 08:20 AM
|
#23
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Hehe, thanks again tronayne  I think I understand what you are trying to say.
Now I can use ndays and dur to find the difference b/w 2 dates
Btw, the average of your, mine, and re_nelson's ages is 40747 days 
|
|
|
11-29-2013, 11:52 AM
|
#24
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Ok,taking suggestions from jtsn I changed the header file (now its stringfunc.h, and doesnt include <string.h>) and rewrote all the functions that I needed
Now its doing some error handling, but not all, which I dont understand
Code:
./dur 0 0
Invalid arguments. The arguments are like yyyy-mm-dd yyyy-mm-dd where the first is the initial date and the next is the final date.
./dur 00 02
Invalid arguments. The arguments are like yyyy-mm-dd yyyy-mm-dd where the first is the initial date and the next is the final date.
./dur 00 022
Invalid arguments. The arguments are like yyyy-mm-dd yyyy-mm-dd where the first is the initial date and the next is the final date.
./dur 00 0223
Segmentation fault
./dur 000 0223
Segmentation fault
./dur 2013-01-01 `date +%F`
332 day(s)
I also tried to implement re_nelson's suggestion of correcting the code which the compiler thinks is incorrect (didnt get all the way though yet)
Interested parties can take a look at the code.
https://github.com/aadityabagga/dur
Edit-
Mods if you feel this is getting off-topic, you can split this topic. 
Last edited by aaditya; 11-29-2013 at 12:29 PM.
|
|
|
11-29-2013, 12:37 PM
|
#25
|
Member
Registered: Apr 2010
Distribution: Slackware
Posts: 497
Rep: 
|
Quote:
Originally Posted by aaditya
It took some time and effort (its 200 lines of code + testing for different cases!(also available)), but finally I made it! 
|
I hate doing this to you, but the core logic can be done in 3 lines of code  kudos for the effort though.
cf. http://alcor.concordia.ca/~gpkatch/
|
|
1 members found this post helpful.
|
11-29-2013, 12:47 PM
|
#26
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by Martinus2u
|
Ah, Thank You 
Didnt know about this before 
I think that this implementation uses the modified Julian day method mentioned by tronayne in this thread.
|
|
|
11-29-2013, 09:57 PM
|
#27
|
Member
Registered: Sep 2011
Posts: 925
|
Quote:
Originally Posted by aaditya
Ok,taking suggestions from jtsn I changed the header file (now its stringfunc.h, and doesnt include <string.h>) and rewrote all the functions that I needed 
|
Function definitions still don't belong to header files. the go into .c files, header files only contain #defines of CONSTANTs, data types and extern declarations (aka function prototypes).
If think, you first need a good book on C, because whatever study material you currently using, it is completely worthless. You didn't understand what a "header guard" does...
Now, instead of implementing the date extraction without calling any string functions (which is possible), you implemented some string functions yourself. Which is a good beginner's exercise, too. So lets have a look at your code:
Code:
unsigned int length(char* string)
{
int len=0;
char c=*string; /*The first character of the string*/
while(c!='\0')
{
len=len+1; /*len incremented on reading each character*/
c=*(string+len); /*now point to next character*/
}
return len;
}
So who does teach you this sort of over-complicated stuff? How could a standard library function like strlen() be implemented? Like this:
Code:
size_t strlen(char *s)
{
size_t len = 0;
while(*s++)
len++;
return len;
}
Now try to understand that code and how exactly it works. (It does exactly the same thing as your "length()" function). You don't learn C by writing code, you learn it by reading and understanding code.
As an exercise try to break it down to one line using a single for() statement.
Some notes on the remaining code: You never cast void* pointers in C (the return value of malloc() ), because that disables type checking. You always check the return value of malloc(), because if memory allocation fails, it returns NULL.
It's a good practice to leave memory allocation to the caller of the function and don't return pointers on newly allocated memory. C is not Java, you don't have garbage collection, so you have to free() everything, what you allocate with malloc()...
Quote:
Mods if you feel this is getting off-topic, you can split this topic.
|
I think this thread should go into the "Programming" LQ forum. And of course, it can't replace a good lecture on C programming.
|
|
2 members found this post helpful.
|
11-30-2013, 12:25 AM
|
#28
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Thank you for your advice and time  I will try to address your points one by one.
Ok, functions should go in .c files, I mistakenly thought that header files contained functions, becuase I include <stdio.h> to use printf 
I checked stdio.h in /usr/include and it doesnt have any functions.
I read about header guards yesterday on Wikipedia after searching for header files in C.
Understood what your function is doing. Here is the exercise with the for loop-
Code:
size_t strlenx(char *s)
{
size_t len=0;
for(;*s++;len++);
return len;
}
Will read more on malloc().
Understood your point about memory allocation being left to the caller function.
Will try to improve the code.
Thanks 
|
|
|
11-30-2013, 08:14 AM
|
#29
|
Senior Member
Registered: Oct 2003
Location: Northeastern Michigan, where Carhartt is a Designer Label
Distribution: Slackware 32- & 64-bit Stable
Posts: 3,541
|
I humbly suggest that you may benefit from a book, perhaps two.
At least get a copy of Brian W. Kernighan, Dennis M. Ritchie The C Programming Language (2nd ed: Englewood Cliffs, New Jersey: Prencitce-Hall Inc., 1978, ISBN 0-13-110362-8) from Amazon.com or whatever source you have available to you. It's the "bible," written by the guys that invented C and written in an easy-to-understand way that explains everything clearly. Invaluable on your bookshelf.
I highly recommend Stephen G. Kochan Programming in C (3rd ed.: New York: Sams Publishing, 2004, ISBN 978-0672326660). This is a how-to, why-to, what-to-do that is written clearly, full of useful examples, well worth your time and an excellent learning tool.
Hope this helps some.
|
|
2 members found this post helpful.
|
11-30-2013, 10:41 AM
|
#30
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Thanks tronayne 
I already have the K&R C (ebook,havent read it all though) 
I have studied from the the 2nd one as well (dont have it though) 
Edit-2nd one also downloaded.
Plus I have in hard copy, http://www.amazon.com/Let-Us-Yashava.../dp/8176566217 (with solutions) 
|
|
|
All times are GMT -5. The time now is 08:33 AM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|