My iprintf function repeats the same string e.g.:
iprintf("[USER] created user:%d", userID);
iprintf("[USER] user disconnected:%d, userID");
I am trying to save some space and do something like this
const char strUser[] = "[USER]";
iprintf(strUser + "created user:%d", userID);
iprintf(strUser + "user disconnected:%d", userID);
What in C language can replace the "+" so it will work?
I am trying to keep at least part of the string as a parameter.
And do it during compilation with no extra functions
If and how much space any attempt at optimization saves depends on the compiler. There is usually an option for a "minimum size build". Compiling the program and checking the results is the only method to see if space was truly saved. There is a good chance that any compiler, aiming for a minimum size build, that sees const char strUser[] = "[USER] "; will create exactly one string in the program, and point to that string wherever it is used.
Here are three options you could try. One using a macro, one using a function, and one using a different function call. I know you asked for "during compilation with no extra functions", but this function may very well be "optimized away" during compilation.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
// warning: ISO C does not permit named variadic macros
#define IPRINTF1(format, args...) printf("[USER] " format, ##args);
// An iprintf wrapper that first prints the desired string.
void iprintf2(const char *restrict format, ...)
{
printf("[USER] ");
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
int main(void)
{
const int userID = 5;
const char strUser[] = "[USER] ";
IPRINTF1("created user:%d\n", userID);
iprintf2("created user:%d\n", userID);
// Passing the string as an additional parameter.
// This may be the best solution code quality-wise, as it avoids repetition while keeping the code dynamic.
printf("%screated user:%d\n", strUser, userID);
}
Actually concatenating two strings with + as in Python is not possible in C. Instead there is the strcat function. However, this involves allocating a buffer that is large enough, making a copy of the format string, always guaranteeing that the restrict qualifier holds... This is almost certainly not worth it.
Also, this is all under the assumption that saving a couple of bytes is worth the decrease in code quality.
Related
Setup
#define functionA(str) functionB(PSTR(str))
void functionB(char const* str) { ... something, e.g. print str... }
void functionC(char const* str) {
functionA("Hello World"); // this one work
functionA(str); // however this doesn't work
}
Problem
I have a function function B which I try to use. If I simply call it with "some string" it works perfectly. However if I try to call it in functionC with the argument str, the compiler returns the error "invalid initializer" and the message "in expansion of macro PSTR". How can I fix this, where is my problem?
EDIT - additional information
The program runs on an AT Mega and the PSTR is also from AT-Mega
#define PSTR(s) ((const PROGMEM char *)(s))
#else /* !DOXYGEN */
/* The real thing. */
# define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
#endif /* DOXYGEN */
#define PROGMEM __ATTR_PROGMEM__
#ifndef __ATTR_PROGMEM__
#define __ATTR_PROGMEM__ __attribute__((__progmem__))
#endif
You cannot mix program space and regular strings, since they are stored in different memory spaces. The AVR architecture separates data and program memory, and regular variables/strings live in the data memory (RAM). But since RAM is often very limited on these devices, constant data (such as strings) may be stored in program space to avoid using RAM. The PSTR macro is provided to do this for string literals.
The reason for your error with functionA(str) is simply that it ends up using the macro as PSTR(str), and PSTR only works with string literals since you cannot place data in program space at runtime. But also note that while PSTR("Hello world") works, your functionB must specifically expect a program space string or it will treat the pointer as though it pointed to RAM (which it doesn't).
To use a program space string, you may either take a PSTR as an argument and handle it with the pgm_* functions/macros (such as pgm_read_byte), or first copy the PSTR to RAM (such as with strcpy_P) and then pass that to a function expecting a regular string. See avr/pgmspace.h.
For debugging purposes I am trying to make a short macros to display various types, instead of constant copying all the MessageBox functions' params.
For strings I have following macros:
#define DEBUG(x) MessageBox(NULL, x,"DEBUG",MB_ICONINFORMATION|MB_OK);
Calling it working great, whether I pass variable (array of char) or direct string.
Now, I try to make the same thing for int. Have defined macros like this:
#define STRIGIFY(x) #x
#define TOSTRING(x) STRIGIFY(x)
#define DEBUGINT(x) DEBUG(TOSTRING(x))
It works only in case I pass direct integer value:
DEBUGINT(742);
However if I pass int variable, MessageBox displays variable name instead of its value:
int count = 3;
DEBUGINT(count);
The thing I find pretty interesting for me is that I can pass literally anything in DEBUGINT macros and it will still work:
DEBUGINT(some unescaped string)
How do I define a macros that would use a variable value instead of its name?
This doesn't answer the question as it was asked, but I'll risk my reputation and suggest a different solution.
PLEASE, do yourself a favor and never use MessageBox() or other modal UI to display debug information. If you do want to interrupt program execution at that point, use the breakpoint; it also allows you to attach the condition, so that you don't need to examine the value manually.
If you do not want the interruption, just print the value to a debug output window using ::OutputDebugString(). That can be seen in the debugger if it is attached, or via DebugView tool.
Another small suggestion (for Visual Studio users): if you prepend your output with a source file name and the code line number, double-clicking on that line in the output window will take you straight to that line. Just use __FILE__ and __LINE__ in your formatted string.
You can't. The preprocessor doesn't know anything about variables or their values, because it doesn't do anything run-time only at compile-time.
You can use variable argument list
#include <stdio.h>
void message(const char* format, ...)
{
int len;
char *buf;
va_list args;
va_start(args, format);
len = _vscprintf(format, args) + 1; //add room for terminating '\0'
buf = (char*)malloc(len * sizeof(char));
vsprintf_s(buf, len, format, args);
MessageBoxA(0,buf,"debug",0);
//OutputDebugStringA(buf);
free(buf);
}
message("test %s %d %d %d", "str", 1, 2, 3);
You might also want to change to unicode version.
You need to "print" the variable to a buffer (array of char) using something like sprintf (or snprintf in VS 2015) and pass the resulting output to MessageBox as the string to be displayed.
Please read until the end before you say: "Oh no, this question again..."
I am right now seating in a C course and the following example has been provided in course book:
#include <stdio.h>
#include <stdint.h>
void Terminal_PrintData(uint16_t * const Data);
int main(void){
uint16_t StringData[] = "MyData";
Terminal_PrintData(StringData);
}
void Terminal_PrintData(uint16_t * const Data)
{
printf("Value: %s", *Data);
}
When I compile this masterpiece, this is what I get:
F:\AVR Microcontroller>gcc -o test test.c
test.c: In function 'main':
test.c:7:26: error: wide character array initialized from non-wide string
uint16_t StringData[] = "MyData";
My questions are:
Is it correct to declare a string with uint16_t?
What is recommended way to pass a string to a function?
Your immediate questions:
Is it correct to declare a string with uint16_t?
No.
All strings are always char[]. There ar also wide strings (strings of wide characters), which have the type wchar_t[], and are written with an L prefix (e.g. L"hello").
What is recommended way to pass a string to a function?
As a pointer to the first character in the string, so either char * or wchar_t *. The const qualifier makes no sense here; it would mean that the pointer (not the string itself) is constant (see here). I'd recommend writing wchar_t const * or const wchar_t * instead; it has a different meaning (i.e. the string can't be changed), but it's correct and meaningful.
You mention that this code is from a course book. I'm not sure whether you mean that these are lecture notes handed out by your professor, or whether you bought a published book. In either case, if this snippet is representative of the quality of the book/notes, get a refund.
For now, let's make this code work.
There's an error in this code that will cause the program to crash:
printf("... %s ...", ..., *string, ...) when string is a char* is always wrong. Don't dereference that pointer.
If you insist on using "wide" characters (which is questionable), you're going to have to change a few things:
Rather than using char, you need to include <wchar.h> and use wchar_t instead. As far as I know, uint16_t and uint8_t won't work unless you use explicit casting everywhere. That's because char doesn't have 8 bits, but CHAR_BIT bits.
Wide character literals must start with an L prefix.
Rather than using printf, you need to use wprintf.
In the format string, use %ls rather than %s. (Unless you use Microsoft's compiler.)
Finally, some less grave errors:
As noted, T * const arguments are useless. The author probably meant T const * (or equivalently const T *).
You can remove <stdint.h> and <stdio.h>. We're no longer using uint16_t, and <wchar.h> declares some wide character <stdio.h>-like functions.
I end up with the following code:
#include <wchar.h>
void Terminal_PrintData(wchar_t const * Data);
int main(void){
wchar_t StringData[] = L"MyData";
Terminal_PrintData(StringData);
}
void Terminal_PrintData(wchar_t const * Data)
{
wprintf(L"Value: %ls", Data);
}
This compiles and runs as expected with both GCC and Clang on Linux x86-64.
There are two kinds of strings: "non-wide" ones which consist of chars and "wide" ones which consist of wchar_ts and are written as L"" (single wchar_ts can be written as L''). There are functions to convert between them; apart from these, you cannot intermix them.
Depending on the system, a wchar_t can be 16 or 32 bits wide.
You should view your string as an array of characters (in this case, 8-bit characters) so a uint8_t would suffice. What you normally do is pass the beginning of the string (which is the pointer to the array) to your function. To make it safer, you could also pass the length of the string as an argument, but normally your string will end with a delimiter (\0).
when you pass stringData to your function, you're actually saying &stringData[0], literally "the address (&) of the first element ([0]) of the array".
Edit 3: For the code itself all together check the first answer or the end of this post.
As stated in the title I'm trying to find a way to tell if an optional argument was passed to a function or not. What I'm trying to do is something like how almost all dynamic languages handle their substring function. Below is mine currently, but it doesn't work since I don't know how to tell if/when the thing is used.
char *substring(char *string,unsigned int start, ...){
va_list args;
int unsigned i=0;
long end=-1;
long long length=strlen(string);
va_start(args,start);
end=va_arg(args,int);
va_end(args);
if(end==-1){
end=length;
}
char *to_string=malloc(end);
strncpy(to_string,string+start,end);
return to_string;
}
Basically I want to still be able to not include the length of the string I want back and just have it go to the end of the string. But I cannot seem to find a way to do this. Since there's also no way to know the number of arguments passed in C, that took away my first thought of this.
Edit:
new way of doing it here's the current code.
#define substring(...) P99_CALL_DEFARG(substring, 3, __VA_ARGS__)
#define substring_defarg_2 (0)
char *substring(char *string,unsigned int start, int end){
int unsigned i=0;
int num=0;
long long length=strlen(string);
if(end==0){
end=length;
}
char *to_string=malloc(length);
strncpy(to_string,string+start,end);
return to_string;
}
and then in a file I call test.c to see if it works.
#include "functions.c"
int main(void){
printf("str:%s",substring("hello world",3,2));
printf("\nstr2:%s\n",substring("hello world",3));
return 0;
}
functions.c has an include for functions.h which includes everything that is ever needed. Here's the clang output(since clang seems to usually give a bit more detail.
In file included from ./p99/p99.h:1307:
./p99/p99_generic.h:68:16: warning: '__error__' attribute ignored
__attribute__((__error__("Invalid choice in type generic expression")))
^
test.c:4:26: error: called object type 'int' is not a function or function
pointer
printf("\nstr2:%s\n",substring("hello world",3));
^~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from test.c:1:
In file included from ./functions.c:34:
In file included from ./functions.h:50:
./string.c:77:24: note: instantiated from:
#define substring(...) P99_CALL_DEFARG(substring, 3, __VA_ARGS__)
GCC just says the object is not a function
Edit 2: Note that setting it to -1 doesn't change it either, it still throws the same thing. The compile options I'm using are as follows.
gcc -std=c99 -c test.c -o test -lm -Wall
Clang is the same thing(whether or not it works with it is another question.
ANSWER HERE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include "p99/p99.h"
#define substring(...) P99_CALL_DEFARG(substring, 3, __VA_ARGS__)
#define substring_defarg_2() (-1)
char *substring(char *string, size_t start, size_t len) {
size_t length = strlen(string);
if(len == SIZE_MAX){
len = length - start;
}
char *to_string = malloc(len + 1);
memcpy(to_string, string+start, len);
to_string[len] = '\0';
return to_string;
}
You will need p99 from there. It is by the selected answer. Just drop into your source directory and you should be OK. Also to summarize his answer on the license. You're able to use it however you want, but you cannot fork it basically. So for this purpose you're free to use it and the string function in any project whether proprietary or open source.
The only thing I ask is that you at least give a link back to this thread so that others who happen upon it can learn of stack overflow, as that's how I do my comments for things I've gotten help with on here.
In C, there's no such thing as an optional argument. The common idiom for situations like this is to either have two functions; substr(char *, size_t start, size_t end) and substr_f(char *, size_t start) or to have a single function where end, if given a special value, will take on a special meaning (such as in this case, possibly any number smaller than start, or simply 0).
When using varargs, you need to either use a sentinel value (such as NULL) at the end of the argument list, or pass in as an earlier argument the argc (argument count).
C has a very low amount of runtime introspection, which is a feature, not a bug.
Edit: On a related note, the correct type to use for string lengths and offsets in C is size_t. It is the only integer type that is guaranteed to be both large enough to address any character in any string, and guaranteed to be small enough to not be wasting space if stored.
Note too that it is unsigned.
Other than common belief functions with optional arguments can be implemented in C, but va_arg functions are not the right tool for such a thing. It can be implemented through va_arg macros, since there are ways to capture the number of arguments that a function receives. The whole thing is a bit tedious to explain and to implement, but you can use P99 for immediate use.
You'd have to change your function signature to something like
char *substring(char *string, unsigned int start, int end);
and invent a special code for end if it is omitted at the call side, say -1. Then with P99 you can do
#include "p99.h"
#define substring(...) P99_CALL_DEFARG(substring, 3, __VA_ARGS__)
#define substring_defarg_2() (-1)
where you see that you declare a macro that "overloads" your function (yes this is possible, common C library implementations use this all the time) and provide the replacement with the knowledge about the number of arguments your function receives (3 in this case). For each argument for which you want to have a default value you'd then declare the second type of macro with the _defarg_N suffix, N starting at 0.
The declaration of such macros is not very pretty, but tells at least as much what is going on as the interface of a va_arg function would. The gain is on the caller ("user") side. There you now can do things like
substring("Hello", 2);
substring("Holla", 2, 2);
to your liking.
(You'd need a compiler that implements C99 for all of this.)
Edit: You can even go further than that if you don't want to implement that convention for end but want to have two distinct functions, instead. You'd implement the two functions:
char *substring2(char *string, unsigned int start);
char *substring3(char *string, unsigned int start, unsigned int end);
and then define the macro as
#define substring(...) \
P99_IF_LT(P99_NARG(__VA_ARGS__, 3)) \
(substring2(__VA_ARGS__)) \
(substring3(__VA_ARGS__))
this would then ensure that the preprocessor chooses the appropriate function call by looking at the number of arguments it receives.
Edit2: Here a better suited version of a substring function:
use the types that are semantically correct for length and stuff like
that
the third parameter seems to be a length for you and not the end of the string, name it accordingly
strncpy is almost never the correct function to chose, there are situations where it doesn't write the terminating '\0' character. When you know the size of a string use memcpy.
char *substring(char *string, size_t start, size_t len) {
size_t length = strlen(string);
if(len == SIZE_MAX){
len = length - start;
}
char *to_string = malloc(len + 1);
memcpy(to_string, string+start, len);
to_string[len] = '\0';
return to_string;
}
Unfortunately, you cannot use va_arg like that:
Notice also that va_arg does not determine either whether the retrieved argument is the last argument passed to the function (or even if it is an element past the end of that list). The function should be designed in such a way that the amount of parameters can be inferred in some way by the values of either the named parameters or the additional arguments already read.
A common "workaround" is to give the other "overload" a nice mnemonic name, such as right_substr. It will not look as fancy, but it will certainly run faster.
If duplicating implementation is your concern, you could implement left_substr, substring, and right_substr as wrappers to a hidden function that takes start and length as signed integers, and interprets negative numbers as missing parameters. It is probably not a good idea to use this "convention" in your public interface, but it would probably work fine in a private implementation.
In standard C, when using variable argument prototypes (...), there is no way to tell directly how many arguments are being passed.
Behind the scenes, functions like printf() etc assume the number of arguments based on the format string.
Other functions that take, say, a variable number of pointers, expect the list to be terminated with a NULL.
Consider using one of these techniques.
I know it's quite idiomatic, or good style at least, in C to declare numeric constants as enums instead of #defineing them.
/* bad style */
#define MAXLINE 1024
/* good/better style */
enum {
MAX_LINE = 1024
};
Is there an equivalent rule for the definition of string constants?
/* is this good style? */
#define HELLO "Hello World"
/* or is this better? */
const char *HELLO2 = "Howdy";
What do you prefer? If possible show some drawbacks of either method.
There's one more (at least) road to Rome:
static const char HELLO3[] = "Howdy";
(static — optional — is to prevent it from conflicting with other files). I'd prefer this one over const char*, because then you'll be able to use sizeof(HELLO3) and therefore you don't have to postpone till runtime what you can do at compile time.
The define has an advantage of compile-time concatenation, though (think HELLO ", World!") and you can sizeof(HELLO) as well.
But then you can also prefer const char* and use it across multiple files, which would save you a morsel of memory.
In short — it depends.
One advantage (albeit very slight) of defining string constants is that you can concatenate them at compile time:
#define HELLO "hello"
#define WORLD "world"
puts( HELLO WORLD );
Not sure that's really an advantage, but it is a technique that cannot be used with const char *'s.
If you want a "const string" like your question says, I would really go for the version you stated in your question:
/* first version */
const char *HELLO2 = "Howdy";
Particularly, I would avoid:
/* second version */
const char HELLO2[] = "Howdy";
Reason: The problem with second version is that compiler will make a copy of the entire string "Howdy", PLUS that string is modifiable (so not really const).
On the other hand, first version is a const string accessible by pointer HELLO2, and it can not be modified.
The main disadvantage of the #define method is that the string is duplicated each time it is used, so you can end up with lots of copies of it in the executable, making it bigger.
Their are a few differences.
#define HELLO "Hello World"
The statement above can be used with preprocessor and can only be change in the preprocessor.
const char *HELLO2 = "Howdy";
The statement above can be changed with c code. Now you can't change the each individual character around like the statement below because its constant.
HELLO2[0] = 'a'
But you what you can do is have it point to a different string like the statement
below
HELLO2 = "HELLO WOLRD"
It really depends on how you want to be able to change the variable around.
With the preprocessor or c code.