Re: C function prototype



I had to rush off to an appointment, and thought of a few more things along the way.

First, the existence of the CRT does not prove that the functions are particularly
well-designed, or even appropriate for modern programming. The new CRT, first delivered
with VS2005, uses "safe" functions, like strcpy_s, which are the ONLY forms of CRT
functions that should be used. If you do not have VS2005, you can download the Platform
SDK and use the functions in strsafe.h instead; they are also safe. But the following
functions should NEVER be used, even in existing programs.
strcpy
strcat
sprintf
itoa
itof
there are probably more, but these are functions so bad that it is essentially insane to
use them, particularly in the way you are doing. Your techniques are the kind of
techniques that lead to headlines of the form "300,000 computers crippled in first hour of
the KILLME virus attack...", and you do not EVER want to be part of a project that can
generate such headlines. The above functions are particularly good ways to get those
headlines, and therefore must be absolutely avoided.

ANother thing: if you have a pointer to something that is being read but not written, you
should ALWAYS include the word 'const' in the declaration. For example, the prototype of
your stradd should be

void stradd(LPTSTR dest, SIZE_T len, LPCTSTR src);
which, in an ANSI build, turns into
void stradd(char * dest, size_t len, const char * src);
and in a Unicode build turns into
void stradd(wchar_t * dest, size_t len, const wchar_t * src);

the len is a critical parameter; it is YOUR responsibility to see that under NO IMAGINABLE
CONDITIONS will more characters be copied into dest than len allows, including the
terminating NUL character (this is what strcat_s does, for example). Any other approach
is an invitation to complete, flaming disaster, the kind that makes the aforementioned
headlines.

But ultimately, think of the string-handling capabilities of the CRT as dead, dead, dead,
dead. Use CString in ATL/MFC apps, or std::string in other apps, and never, ever use the
unsafe versions of the CRT routines for ANYTHING.

And ALWAYS think of 'char' as a rare and exotic data type, never used for real programming
of strings. It is used in very, very limited ways, when you absolutely, positively know
you have only 8-bit character data, which is essentially almost never.

Develop good habits when you start programming, that way you don't have to unlearn all the
bad habits later.

More below...
On Sat, 12 Apr 2008 19:18:29 -0400, Joseph M. Newcomer <newcomer@xxxxxxxxxxxx> wrote:

On Sat, 12 Apr 2008 15:47:37 -0700, June Lee <iiuu66@xxxxxxxxx> wrote:

Is that for Class/Object function prototype, I must define the
function in header file or .cpp file.

MyClass::functionA();
MyClass::functionB();

but for C function prototype, I don't have to define if it's put
before the main() function the following is not needed -

void stradd (char *s1, char *s2);
void stradd (char *s1, int i);
****
First rule: forget the data type 'char' exists except in very rare and exotic situations,
of which this is not one. 'char' is effectively obsolete for modern programming.

void stradd(LPTSTR s1, LPTSTR s2);
void stradd(LPTSTR s1, int i);

Note that your fundamental design is flawed beyond redemption, because you are using
strcat, which is now VERY obsolete and whose existence should be ignored. It is unsafe.
It should NEVER be used.

The correct declarations for modern programming would be

void stradd(CString & s1, const CString & s2);
void stradd(CString & s1, int i);

because CString is a correctly-handled type that can never have a buffer overrun when used
correctly.

Since you are clearly learning C, it is critical that you do NOT develop bad programming
habits early. Use of 'char', use of 'strcat', are now considered VERY BAD programming
style.
****

=========
#include <iostream> // cannot be iostream.h??
#include <stdio.h>
#include <string.h>


#include <comdef.h>
#include <conio.h>
****
You shoud not conio for anything;
****
#include <windows.h> // must need for SYSTEMTIME

//must need C/C++ > General > Debug Information Format to debug
working

using namespace std; // for cout must have??

// concatenate two strings
void stradd (char *s1, char *s2)
{
strcat (s1, s2); // CRT <string.h> function
****
This is so unbelievably unsafe that no sane programmer would write this code today. DO
NOT use strcat! It is UNSAFE.
****
}

// concatenate a string with a "stringized" integer
void stradd (char *s1, int i)
{
char temp[80];

sprintf (temp, "%d", i);
strcat (s1, temp);
****
There are so many things wrong here it is mind boggling. You are using 'char'. You are
using a fixed-size array; you are using sprintf, which is unsafe, and you are using
strcat, which is unsafe. The CORRECT way to write this code in MFC/ATL is
void stradd(CString & s1, int i)
{
CString s;
s.Format(_T("%d"), i);
s1 += s;
}

This is the only acceptable style of coding that should be used. You can also use
std::string, but CString is well-integrated into MFC and ATL and is the preferred class.
But fixed-size buffers, strcat, strcpy, and sprintf should NEVER enter your programming
vocabulary. They are so bad that if they did not already exist, nobody would be dumb
enough to create them! (I thought they were a stupid idea in 1975 when I first discovered
C, and guess what, 30 years later everyone seems to have made the same discovery!)
****
}



int main()
{
//SYSTEMTIME st = {0,0,0,0,0,0,0,0}; // cannot divide into 2
lines - must init all in one line
****
The above comment is not true; it can be multiple lines!
SYSTEMTIME
st
=
{
0
.
and so on!
****
The C language treats newline as whitespace in ALL contexts except #define lines (where
you need to put a \ at the end of the line to cause the next line to be part of the
#define) and in quoted literals (where it is not permitted at all). What you can't do is
an assignment of a structured type as a second assignment statement, because C has no
syntax to represent aggregate literals. But that's not the same as saying the
initialization can't be divided into multiple lines.
****
SYSTEMTIME st = {0}; // OK too

char str[80];
//char* str; // not OK will crash program
****
Yes. The declaration 'char * str' makes no sense, because it is an uninitialized pointer
to a string. As such, it does not reference an actual string; you would have to allocate
space to hold the string, and assign a pointer to that space to this variable.

It makes as much sense to code this as to write
int i;
i++;
what value do you think 'i' will have at this point? Right, some unknown and unknowable
value, because i was never initialized in the first place, so adding 1 to an uninitialized
value will create a meaningless value. char * str is essentially the identical problem.
Had you written
char * str = (char *)malloc(80);
or
char * str = new char[80];
it would work, except that you still have a fixed size buffer and the same errors apply
about buffer overrun, and then you have to additionally delete the buffer.
*****

strcpy (str, "Hello ");
stradd (str, "there");
****
And then you do
stradd(str, "this is a");
stradd(str, "test of a very");
stradd(str, "long string which is going to");
stradd(str, "cause the buffer to overflow and");
stradd(str, "totally destroy my execution");
and what happens? (Never mind, I just explained it...). This is why strcat is forbidden.
If you had use strcat_s, you would have written
stradd(str, 80, "this is a");
stradd(str, 80, "test of a very");
stradd(str. 80, "long string which is going to");
and so on, then it would actually not overrun the buffer, and you would not have your
execution environment destroyed (your program will die with an access fault at some point,
perhaps on the return from the function, perhaps earlier, depending on what is destroyed).
*****
cout << str << "\n";

stradd (str, 100);
cout << str << "\n";

stradd (str, "hihi");
cout << str << "\n";

****
The term for what you have done is officially "C programmer's disease" and is
characterized by creating buffers that are too small to hold the data. (See: the Jargon
File). It has been a defect in the C language since its creation, and there is no reason
to fall into the same trap that 30 years of C programmers fell into. The best thing to
learn about the low-level CRT routines is when *NOT* to use them, and this is a prime
example of such a case
joe
****
return 0;
}

Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.



Relevant Pages

  • Re: Best book on learning C++?
    ... >> bits in a char for example. ... >> and the newbie should not be smothered with such technical ... It was her first programming course and she needed some ... >void main ...
    (alt.comp.lang.learn.c-cpp)
  • Re: There are lots of things that can be done to increase the complexity of hidden data
    ... void byteshuffle(unsigned char *list,unsigned char *password, unsigned ... void BShift(unsigned char *A, bool LR, unsigned int distance,unsigned ... When I worked for DOD one of my job functions was programming material ...
    (sci.crypt)
  • Re: asm
    ... I'm new to programming and I have seen very little. ... int main ... #define UC unsigned char ... void free_node ...
    (alt.lang.asm)
  • [PATCH 2.6.19-rc1 V9] drivers: add LCD support
    ... Adds support for the ks0108 LCD Controller as a device driver. ... +The buffer should be a 128*64 unsigned char array: ... * GNU General Public License for more details. ... +static void cfag12864b_setbit ...
    (Linux-Kernel)
  • [PATCH 2.6.19-rc1 V9] drivers: add LCD support
    ... Adds support for the ks0108 LCD Controller as a device driver. ... +The buffer should be a 128*64 unsigned char array: ... * GNU General Public License for more details. ... +static void cfag12864b_setbit ...
    (Linux-Kernel)

Quantcast