How can I pass a string value to a function in C - c

This bothers me. It gives me a warning of
passing argument 1 of ‘funcName’ discards qualifiers from pointer target type
however, the program to run just fine and printing the submitted value.
The functions are the following
void funcName(char *str) {
printf("%s", str);
}
void main() {
funcName("Hello world");
}
output is Hello world.

It's because "Hello, world" is constant, so change the function to
void funcName(const char *text)
{
printf("%s\n", text);
}
String literals are constant, they are stored in a read only memory section of your program, passing the pointer without const means that you can accidentally modify it inside the target function, if you do so, that would cause undefined behavior, and the compiler is trying to protect you from that.
Also, void main() is not a standard compliant valid signature for main(), you can find it in old books, previous to the standard, but now it's no longer accepted, accepted and standard signatures are
int main(void) If you don't handle command line arguments.
int main(int argc, char **argv) To handle argc parameteres stored in argv that where passed in the command line.

It seems that the problem is that this C program is compiled as a C++ program.
In C++ string literals have types of constant character arrays. So if in a C++ program you supply a string literal as an argument to a function that has the corresponding parameter without the qualifier const then the compiler will issue a message.
If to compile the program as a C program then the code is valid because in C string literals have types of non-constant character arrays and the compiler should not issue a diagnostic message relative to qualifiers.
Nevertheless in any case it is better to declare the function like
void funcName( const char *str );
^^^^^^
because in this case the user of the function can be sure that the string passed to the function will not be changed.
Take into account that function main without parameters shall be declared in C like
int main( void )

Related

Confused on "pass by reference" in C and when to use an & or *

I'm not as knowledgeable in C as I thought I was, but can anyone explain to me what I'm doing wrong here ? I am writing a program for an embedded system using a Texas Instruments microcontroller using UARTS (an asynchronous receiver transmitter on the microcontroller). UART libraries are usually included when I'm building a project.
Anyway, here is my issue: I have 4 functions that just prints a string to the console and my code compiles, but it gives me warnings and not compilation errors.
void foward(unsigned char *command) {
UARTPutString(UART_BASE, &command);
}
void reverse(unsigned char *command) {
UARTPutString(UART_BASE, &command);
}
void left(unsigned char *command) {
UARTPutString(UART_BASE, &command);
}
void right(unsigned char *command) {
UARTPutString(UART_BASE, &command);
}
My issue mainly lines with when to use a pointer in the simplest sense. The reason why I used a pointer for char* command is because the imported library was written like that, but I have no idea why we have to use a char pointer. And what do you put as the second argument in:
UARTPutString(UART_BASE, &command);
When do I use &, or * ? I know pointers point to the memory address of something, but it's not clicking to me on when I need to use *, &, and so forth when using it as parameters for a function.
This warning is mentioned 21 times for some reason:
Description Resource Path Location Type
#169-D argument of type "unsigned char **" is incompatible with parameter of type "unsigned char *" uartconsole.c /Command_Line_Interface line 82 C/C++ Problem
Thank for the help !
The 2nd argument to UARTPutString() is supposed to be a string, which is a char * value -- a string is a pointer to a sequence of characters.
command is declared to be char *, so you should just pass that directly. Adding & creates a pointer to a pointer, which is char **, and incompatible with char *.
UARTPutString(UART_BASE, command);
You use & before a variable when you need to pass the variable by reference. This is usually done if the function needs to modify the variable's value. It may also be used for large structure variables, to avoid making a copy of the variable when passing it to the function.
You need to write:
UARTPutString(UART_BASE, command);
Your command is a pointer (i.e., a variable holding an address) to a character array.
When writing &command you take the address of command. The type of the &command expression is therefore the address of a pointer unsigned char **, which is what the compiler is complaining about.
So that warning is telling you the compiler is expecting just unsigned char * as the second argument of UARTPutString(), which is the type of command.
What is confusing about * in C is that its 'meaning' depends on the place where it's used. In a variable declaration it says that the variable is a pointer. While used in an expression, for example if you would write *command = 0;, it dereferences the pointer; the opposite of when * is used in a declaration.
There's a lot more to say about this and I suggest you read relevant sections of the C-FAQ.
Good luck. C is a very nice language and worth putting the effort in.

Why are strings in C declared with 'const'?

For example, why not:
char *s= "example";
instead of:
const char *s= "example";
I understand that const makes it unchangeable, but why do I receive an error when compiling the first?
Additionally, how does the concept apply to
int * x;
vs
const int *x;
I see the second used a lot more, is it good practice to use "cons int *"?
There's no requirement to use const, but it's a good idea.
In C, a string literal is an expression of type char[N], where N is the length of the string plus 1 (for the terminating '\0' null character). But attempting to modify the array that corresponds to the string literal has undefined behavior. Many compilers arrange for that array to be stored in read-only memory (not physical ROM, but memory that's marked read-only by the operating system). (An array expression is, in most contexts converted to a pointer expression referring to the initial element of the array object.)
It would have made more sense to make string literals const, but the const keyword did not exist in old versions of C, and it would have broken existing code. (C++ did make string literals const).
This:
char *s= "example"; /* not recommended */
is actually perfectly valid in C, but it's potentially dangerous. If, after this declaration, you do:
s[0] = 'E';
then you're attempting to modify the string literal, and the behavior is undefined.
This:
const char *s= "example"; /* recommended */
is also valid; the char* value that results from evaluating the string literal is safely and quietly converted to const char*. And it's generally better than the first version because it lets the compiler warn you if you attempt to modify the string literal (it's better to catch errors at compile time than at run time).
If you get an error on your first example, then it's likely that you're inadvertently compiling your code as C++ rather than as C -- or that you're using gcc's -Wwrite-strings option or something similar. (-Wwrite-strings makes string literals const; it can improve safety, but it can also cause gcc to reject, or at least warn about, valid C code.)
With Visual Studio 2015 at warning level 4, this compiles and runs whether compiled as C or C++:
#include <stdio.h>
char *s1= "example\n";
const char *s2= "example\n";
int main(int argc, char **argv)
{
printf(s1); // prints "example"
s1[2] = 'x';
printf(s1); // prints "exxmple"
printf(s2);
return 0;
}
If I add this line, it will fail to compile as C or C++ with every compiler I know of:
s2[2] = 'x'; // produces compile error
This is the error the const keyword is designed to avoid. It simply tells the compiler not to allow assignments to the object pointed to.
It doesn't matter if your pointer points to char or int or anything else. The const keyword has the same effect on all pointers, and that's to make it impossible (well, very hard) to assign to the thing declared const.
A string literal used as a value compiles to an array of char that should not be modified. Attempting to modify it invokes undefined behavior. For historical reasons of backward compatibility, its type is char [] although is really should be const char []. You can enable extra compiler warnings to change this and instruct the compiler to consider such strings to be const.

%s expects 'char *', but argument is 'char[100]'

I have something along the lines of:
#include <stdio.h>
typedef struct {
char s[100];
} literal;
literal foo()
{
return (literal) {"foo"};
}
int main(int argc, char **argv) {
printf("%s", foo().s);
return 0;
}
And I get this error when compiling it (with gcc):
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2
has type ‘char[100]’ [-Wformat=]
any1 has any ideas on how I can fix it? And what is wrong with that function return type?
EDIT
The problem (if not clear in the discussion) was the c standard gcc was using to compile the file. if you use -std=c99 or -std=c11 it works.
It is not an error but a warning, not all warnings that -Wall produces are sensible.
Here the compiler is "kind-of" right: before evaluation your argument is an array and not a pointer, and taking the address of a temporary object is a bit dangerous. I managed to get rid of the warning by using the pointer explicitly
printf("%s\n", &foo().s[0]);
Also you should notice that you are using a rare animal, namely an object of temporary lifetime, the return value or your function. Only since C99, there is a special rule that allows to take the address of such a beast, but this is a corner case of the C language, and you would probably be better off by using some simpler construct. The lifetime of the pointer ends with the end of the expression. So if you would try to assign the pointer to a variable, say, and use it later on in another expression, you would have undefined behavior.
Edit(s): As remarked by mafso in a comment, with C versions from before C99, it was not allowed to take the address of the return value of the function. As Pascal Cuoq notes, the behavior of your code is undefined even for C99, because between the evaluation of the arguments and the actual call of the function there is a sequence point. C11 rectified this by indroducing the object of temporary lifetime that I mentioned above.
I don't exactly why maybe someone with more knowledge in C than me can explain it but writing main() on this way:
int main(int argc, char **argv) {
literal b = foo();
printf("%s", b.s);
return 0;
}
The code prints "foo" correctly on GCC 4.5.4

Passing c string into function

I have a question regarding passing c string into function.
If I have a function:
void reverse(char* c){
//here is the reverse code
}
In the main:
int main(){
char* c1="abcd";
char c2[5]="abcd";
char * c3=new char[5];
c3="abcd";
}
In my test, only c1 is not allow to pass into the function, other two works fine. I would like to know why c1 is a wrong usage? Thank you very much!
Your code is C++, not C; new char[5] is a syntax error in C.
C and C++ are two different languages. In C++, string literals are const, and passing a string literal to a function that takes a char* argument is an error. You should have gotten an error message (which you haven't bothered to show us) from your C++ compiler.
(If you were using a C compiler, it would have accepted a call like reverse("foo"), but it would have complained about the new char[5].)
c1 will point to a string literal and attempting to modify a string literal is undefined behavior, this is based on the assumption that reverse will attempt to reverse the string in place.

Know if const qualifier is used

Is there any way in C to find if a variable has the const qualifier? Or if it's stored in the .rodata section?
For example, if I have this function:
void foo(char* myString) {...}
different actions should be taken in these two different function calls:
char str[] = "abc";
foo(str);
foo("def");
In the first case I can modify the string, in the second one no.
Not in standard C, i.e. not portably.
myString is just a char* in foo, all other information is lost. Whatever you feed into the function is automatically converted to char*.
And C does not know about ".rodata".
Depending on your platform you could check the address in myString (if you know your address ranges).
You can't differ them using the language alone. In other words, this is not possible without recurring to features specific to the compiler you're using, which is likely not to be portable. A few important remarks though:
In the first case you COULD modify the string, but you MUST NOT. If you want a mutable string, use initialization instead of assignment.
char *str1 = "abc"; // NOT OK, should be const char *
const char *str2 = "abc"; // OK, but not mutable
char str3[] = "abc"; // OK, using initialization, you can change its contents
#include<stdio.h>
void foo(char *mystr)
{
int a;
/*code goes here*/
#ifdef CHECK
int local_var;
printf(" strings address %p\n",mystr);
printf("local variables address %p \n",&local_var);
puts("");
puts("");
#endif
return;
}
int main()
{
char a[]="hello";
char *b="hello";
foo(a);
foo(b);
foo("hello");
}
On compiling with gcc -DCHECK prog_name.c and executing on my linux machine the following output comes...
strings address 0xbfdcacf6
local variables address 0xbfdcacc8
strings address 0x8048583
local variables address 0xbfdcacc8
strings address 0x8048583
local variables address 0xbfdcacc8
for first case when string is defined and initialized in the "proper c way for mutable strings" the difference between the addresses is 0x2E.(5 bytes).
in the second case when string is defined as char *p="hello" the differences in addresses is
0xB7D82745.Thats bigger than the size of my stack.so i am pretty sure the string is not on the stack.Hence the only place where you can find it is .rodata section.
The third one is similar case
PS:As mentioned above this isn't portable but the original question hardly leaves any scope for portability by mentioning .rodata :)
GCC provides the __builtin_constant_p builtin function, which enables you to determine whether an expression is constant or not at compile-time:
Built-in Function: int __builtin_constant_p (exp)
You can use the built-in function __builtin_constant_p to determine if a value is known to be constant at compile-time and hence that GCC can perform constant-folding on expressions involving that value. The argument of the function is the value to test. The function returns the integer 1 if the argument is known to be a compile-time constant and 0 if it is not known to be a compile-time constant. A return of 0 does not indicate that the value is not a constant, but merely that GCC cannot prove it is a constant with the specified value of the `-O' option.
So I guess you should rewrite your foo function as a macro in such a case:
#define foo(x) \
(__builtin_constant_p(x) ? foo_on_const(x) : foo_on_var(x))
foo("abc") would expand to foo_on_const("abc") and foo(str) would expand to foo_on_var(str).

Resources