// K&R syntax
int foo(a, p)
int a;
char *p;
{
return 0;
}
// ANSI syntax
int foo(int a, char *p)
{
return 0;
}
As you see, in K&R style, the types of variables are declared in new lines instead of in the braces. How to convert a K&R function declaration to an ANSI function declaration automatically? Does anybody know such an easy-to-use tool in Linux?
You can use cproto or protoize (part of GCC) to generate function prototypes or convert old style (K&R) functions to ANSI format.
Since You wanna convert a multiline string, you chould consider perl
you have
void old_style( c , a ) char c; int a; { /* some multiline code */ }
and must have
void old_style( char c, int a) {}
So
perl -i.bkp -nle 's/\((void|int|char|float|long) [a-zA-Z0-9_-]*\)([a-zA-Z0-9_-] ?,[a-zA-Z0-9_-] ?)\(.*{\)/\1(\2)/g'
or something like it, would do the trick.
It would be easier to tackle down the correct regex to this if you try it out and post in comments the output of
diff file.c file.c.bkp
for each of your source files.
if you want to create standard C prototypes for a .h file use mkproto.c
mkproto thisoldfile.c > thisoldfile.h
You then could also paste over the old K&R code in the C file definition if desired.
Another answer by Robert contained the following (useful) information before it was deleted for being a 'link-only' answer:
You can find mkproto.c at:
https://www.pcorner.com/list/C
There are plenty of other utilities there.
The site hosts two versions of "mkproto" — MKPROTO.ZIP dated 1989-09-07 and MKPROTOB.ZIP dated 1992-06-27. You have to register with the host site, The Programmer's Corner, to download the files. The files appear about 2/3 of the way down a long page of possible downloads.
My gcc installation had neither cproto nor mkproto. But I did have Vim and I figured out a global substitute to do this one parameter at a time...
:%s/^\(\%(\w\+\%(\s*\*\+\s*\|\s\+\)\)\+\)\(\w\+\)\s*(\#=\(.\{-}\)\([(,)]\)\s*\(\w\+\)\s*\([,)].*\)\n\s*\(.\{-}\)\5\([^;]*\);/\1\2\3\4\7\5\8\6/
where the recorded subexpressions are:
the function return type
the function name
the already-prototyped parameters (if any)
the delimiter before the next K&R parameter to fix - '(' or ','
the next K&R parameter to fix
the following delimiter - ',' or ')' followed by any remaining (unprocessed) K&R parameter identifiers and closing ')'
the parameter's type
the parameter's post-identifier characters (e.g., brackets)
Repeat until no more matches in the file. Note, the pattern presumes the K&R function declaration is on one line, followed by individual parameter declarations on successive lines.
Two applications of this substitute successfully processes:
int main(argc,argv)
int argc;
char *argv[];
{
printf("Hello world!\n");
return 0;
}
into:
int main(int argc,char *argv[])
{
printf("Hello world!\n");
return 0;
}
Related
I'm going through Mr. Stroustrup's "A Tour of C++" book. In section 9.3 String Views, the author gives the following example:
string cat(string_view sv1, string_view sv2)
{
string res(sv1.length()+sv2.length());
char *p = &res[0];
for (char c : sv1) // one way to copy
*p++ = c;
copy(sv2.begin(),sv2.end(),p); // another way
return res;
}
When I try to compile this function, I get following error as std::string class doesn't provide any constructor which takes a single int parameter.
error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(std::basic_string_view<char>::size_type)' 11 | string res(sv1.length()+sv2.length());
I checked the Errata for 2nd printing of A Tour of C++ but there is no mention of this issue.
Is this a bug in the example provide or else I'm missing something else?
Is this a bug in the example provide or else I'm missing something else?
Yes this is an erratum in the book as std::string doesn't have a constructor that has only one parameter of type int(or convertible to int).
Instead it has a constructor std::string::string(size_type, char) that can take a char as the second argument. In particular, from std::string:
fill (6) string (size_t n, char c);
(6) fill constructor:
Fills the string with n consecutive copies of character c.
Thus to resolve the erratum, we should pass a second argument as shown below:
string res(sv1.length()+sv2.length(), '\0');
I'm using VxWorks 6.9 and am trying to use some spyLib.h functions but I'm having issues finding what signature to expect given that the type is variadic.
in vxTypesOld.h I find my type: typedef int (*FUNCPTR) (...);
and in spyLib.h i have my function call : extern void spyReportCommon (FUNCPTR printRtn);
But what function parameters are expected for printRtn ? I guess a c-style string is one but I don't know if each line of the table is a string or if its an array of strings, or even one large string.
I can't start writing the function to parse data from the outputted data until I know in what form that data is passed into the function.
All I know for certain is that it returns an int (e.g. int parsePrint( ???? );)
Here is my attempt at reporting:
#include <vxworks.h>
#include <spyLib.h>
#include <usrLib.h>
int ParseSpy(const char * spyOutput); // this is a guess
void Startup()
{
//startup logic
// the compiler said and int param is expected but the .h had void
spyLibInit(1);
spyCommon(1,50, (FUNCPTR) &ParseSpy);
}
int ParseSpy(const char * spyOutput){} // this is a guess
I'm getting an unexpected compiler error: 'spyCommon' was not declared in scope
but as you can see spyLib.h was included so I'm a bit confused by this.
That looks like a bad design. The print function cannot print if it does not know what the parameters are. At least one parameter is needed to specify what the rest of the parameters are.
Looking at the source and searching for "printRtn" I see that all calls to the print function are expecting a printf like function where the first parameter is a format string. Your function should better be written as
int ParseSpy(const char * spyOutput, ...);
Regarding the missing spyCommon you could try to let VxWorks write the preprocessor output to a file to check what the compiler sees. Maybe you are getting the wrong spylib.h file or something it that file is hidden by #if.
I am printing a line like this
cout<<"Hello //stackoverflow";
And this produces the following output
Hello //stackoverflow
I want to know why it does not give me an error as I commented half of the statement and there should be
missing terminating " character
error.
The grammar of C++ (like most of programming languages) is context-sensitive. Simply, // does not start a comment if it is within a string literal.
For an in depth analysis of this, you'd have to refer to the language grammar, and the string literal production rules in particular.
Informally speaking, the fact that // appears in the quoted string literal means that it does not denote a comment block. The same applies to /* and */.
The converse applies to other constructs, where maximal munch requires parsing into the token denoting the start of a comment block; a space is needed before the pointer dereference operator in
#include <iostream>
using namespace std;
int main() {
int n = 1;
int* p = &n;
cout << 1 / *p; // Removing the final space will fail compilation.
}
In easy terms, This is because everything inside quotes is recognized as a string and so the computer does not evaluate // as the way to start a comment.
I'm in a source code migration and the converter program did not convert concatenation of embedded strings with integers. Now I have lots of code with this kind of expressions:
f("some text" + i);
Since C/C++ will interpret this as an array subscript, f will receive "some text", or "ome text", or "me text"...
My source language converts the concatenation of an string with an int as an string concatenation. Now I need to go line by line through the source code and change, by hand, the previous expression to:
f("some text" + std::to_string(i));
The conversion program managed to convert local "String" variables to "std::string", resulting in expressions:
std::string some_str = ...;
int i = ...;
f(some_str + i);
Those were easy to fix because with such expressions the C++ compiler outputs an error.
Is there any tool to find automatically such expressions on source code?
Easy! Just replace all the + with -&:
find . -name '*.cpp' -print0 | xargs -0 sed -i '' 's/+/-\&/g'
When trying to compile your project you will see, between other errors, something like this:
foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
return f(s -& i);
~ ^~~~
(I'm using clang, but other compilers should issue similar errors)
So you just have to filter the compiler output to keep only those errors:
clang++ foo.cpp 2>&1 | grep -F "error: 'const char *' and 'int *' are not pointers to compatible types"
And you get:
foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
foo.cpp:18:10: error: 'const char *' and 'int *' are not pointers to compatible types
You can try flint, an open-source lint program for C++ developed and used at Facebook. It has blacklisted token sequences feature (checkBlacklistedSequences). You can add your token sequence to the checkBlacklistedSequences function and flint will report them.
in checkBlacklistedSequences function, I added the sequence string_literal + number
BlacklistEntry([tk!"string_literal", tk!"+", tk!"number"],
"string_literal + number problem!\n",
true),
then compile and test
$ cat -n test.cpp
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 void f(string str)
7 {
8 cout << str << endl;
9 }
10
11 int main(int argc, char *argv[])
12 {
13 f("Hello World" + 2);
14
15 f("Hello World" + std::to_string(2));
16
17 f("Hello World" + 2);
18
19 return 0;
20 }
$ ./flint test.cpp
test.cpp(13): Warning: string_literal + number problem!
test.cpp(17): Warning: string_literal + number problem!
flint has two versions (old version developed in C++ and new version in D language), I made my changes in D version.
I'm not familiar with a lot of tools which can do that, but I think grep can be helpful in some measure.
In the root directory of your source code, try:
grep -rn '".\+"\s*+\s*' .
, which can find out all the files which containt a line like "xxxxx" +, hope this can help you find all the lines you need.
If all the integers are constant, you can alter the grep experssion as:
grep -rn '".\+"\s*+\s*[0-9]*' .
And you can also include the ( before the string constant:
grep -rn '(".\+"\s*+\s*[0-9]*' .
This may be not the "correct" answer, but I hope this can help you.
You may not need an external tool. Instead, you can take advantage of C++ one-user-defined-conversion rule. Basically, you need to change the argument of your f function from const char*/std::string to a type, that is implicitly convertible only from either a string literal (const char[size]) or an std::string instance (what you get when you add std::to_string in the expression).
#include <string>
#include <iostream>
struct string_proxy
{
std::string value;
string_proxy(const std::string& value) : value(value) {}
string_proxy(std::string&& value) : value(std::move(value)) {}
template <size_t size>
string_proxy(const char (&str)[size]) : value(str) {}
};
void f(string_proxy proxy)
{
std::cout << proxy.value << std::endl;
}
int main()
{
f("this works"); // const char[size]
f("this works too: " + std::to_string(10)); // std::string
f("compile error!" + 10); // const char*
return 0;
}
Note that this is not going to work on MSVC, at least not in 2012 version; it's likely a bug, since there are no warning emitted either. It works perfectly fine in g++ and clang (you can quickly check it here).
I've found a very simple way to detect this issue. Regular expression nor a lint won't match more complex expressions like the following:
f("Hello " + g(i));
What I need is to somehow do type inference, so I'm letting the compiler to do it. Using an std::string instead of a literal string raises an error, so I wrote a simple source code converter to translate all the string literals to the wrapped std::string version, like this:
f(std::string("Hello ") + g(i));
Then, after recompiling the project, I'd see all the errors. The source code is on GitHub, in 48 lines of Python code:
https://gist.github.com/alejolp/3a700e1730e0328c68de
If your case is exactly as
"some text in quotations" + a_numeric_variable_or_constant
then Powergrep or similar programs will let you to scan all files for
("[^"]+")\s*\+\s*(\w+)
and replace with
\1 + std::to_string(\2)
This will bring the possible matches to you but i strongly recommend first preview what you are replacing. Because this will also replace the string variables.
Regular expressions cannot understand the semantics of your code so they cannot be sure that if they are integers. For that you need a program with a parser like CDT or static code analyzers. But unfortunately i do not know any that can do that. So to sum i hope regex helps :)
PS: For the worst case if the variables are not numeric then compiler will give you error because to_string function doesn't accept anything than numeric values. May be later then you can manually replace only them which i can only hope won't be more.
PS 2: Some may think that Powergrep is expensive. You can use trial for 15 day with full functionality.
You can have a try at the Map-Reduce Clang plugin.
The tool was developped at Google to do just this kind of refactoring, mixing strong type-checking and regexp.
(see video presentation here ).
You can use C++ typecasting operator & create a new class which can overload the operator + to your need. You can replace the int to new class "Integer" & perform the required overloading. This requires no changes or word replacing in the main function invocation.
class Integer{
long i;
std::string formatted;
public:
Integer(int i){i = i;}
operator char*(){
return (char*)formatted.c_str();}
friend Integer operator +( char* input, Integer t);
};
Integer operator +( char* input, Integer integer) {
integer.formatted = input + std::to_string(integer.i);
return integer;
}
Integer i = ....
f("test" + i); //executes the overloaded operator
i'm assuming for function f(some_str + i); your definition should be like this
void f(std::string value)
{
// do something.
}
if you declare some other class like AdvString to implement Operator + for intergers. if your declare your function like this below code. it will work like this implementation f(some_str + i);
void f(AdvString value)
{
// do something.
}
sample implementation is here https://github.com/prasaathviki/advstring
I have the code like this :
#include <stdio.h>
main()
{
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
The C documentation says that the getchar() returns the int value. And in the above program we have assigned c type as an int. And most importantly EOF is a integer constant defined in the header function.
Now if the code changes to something like this:
#include <stdio.h>
main()
{
char c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
This code also works! Wait a min, as per C documentation getchar() returnsint, but see in the above code I'm storing it in char. And C compiler doesn't throw any error. And also in while loop I have compared c which is an char with EOF which is an int and compiler doesn't throw any error and my program executes!
Why does the compiler doesn't throw any error in the above two cases?
Thanks in advance.
No. It simply means that the returned value which is an int, implicitly converts into char type. That is all.
The compiler may generate warning messages for such conversion, as sizeof(int) is greater than sizeof(char). For example, if you compile your code with -Wconversion option with GCC, it gives these warning messages:
c.c:5:7: warning: conversion to 'char' from 'int' may alter its value
c.c:8:8: warning: conversion to 'char' from 'int' may alter its value
That means, you should use int to avoid such warning messages.
I'm afraid that the term "dynamic programming language" is too vaguely defined to make a such a fine distinction in this case.
Though I'd argue that implicit converting to one numeric type to another is not a dynamic language feature, but just syntax sugar.
No. Lets look at wikipedia's definition
These behaviors could include extension of the program, by adding new
code, by extending objects and definitions, or by modifying the type
system, all during program execution. These behaviors can be emulated
in nearly any language of sufficient complexity, but dynamic languages
provide direct tools to make use of them.
What you have demonstrated is that a char and int in C/C++ are pretty much the same, and C/C++ automatically casts between the two. Nothing more. There's no modification of the type system here.
Lets rewrite your code to illustrate what's going on
int main(int argc, char** argv)
{
char c;
c = EOF; /* supposing getchar() returns eof */
return (c == EOF) ? 0 : 1;
}
What should the return value of this program be? EOF is not a char, but you cast it to a char. When you do a comparison, that cast happens again, and it gets squashed to the same value. Another way of rewriting this to make it clear what's going on is:
#include <stdio.h>
main()
{
int c;
c = getchar();
while ((char)c != (char)EOF) {
putchar((char)c);
c = getchar();
}
}
EOF is getting squashed; it doesn't matter how it's getting squashed, it could be squashed to the letter 'M', but since it gets squashed the same way every time, you still see it as EOF.
C will let you do what you want, but you have to accept the consequences. If you want to assign an int to a char then you can. Doesn't make it a dynamic language.
(As an aside, the title of this question should be something like "why does c let me assign an int to a char?" and just contain the final paragraph. But presumably that wouldn't attract enough attention. If it had attracted any upvotes then I'd edit the title, but since it isn't I'll leave it as an example of how not to ask a question.)
If you are not reading 7-bit ASCII data, it is possible that \xFF is valid data. If EOF is \xFFFFFFFF and you return the value of getchar() to a char then you can not distinguish EOF from \xFF as data.