I am creating a C program with some hardcoded parameters. (This is by design, lets not worry about that.)
//global constants
const char * const USERNAME = "username";
const int USERNAME_LEN = strlen(USERNAME);
Of course, this errors out because strlen isn't a constant apparently. Is there a way to do this? or should I just not care and pass strncmp the result direct from strlen?
If you really need your USERNAME as a const char * const object (do you?), then one way to it is
#define USERNAME_LITERAL "username"
const char * const USERNAME = USERNAME_LITERAL;
const int USERNAME_LEN = sizeof USERNAME_LITERAL - 1;
It is as elegant as one might wish, but does keep the code in "self-maintaining" shape. I.e. you only have to edit the literal, the rest will update itself automatically.
You can also do
const char USERNAME[] = "username";
const int USERNAME_LEN = sizeof USERNAME - 1;
or even
#define USERNAME "username"
const int USERNAME_LEN = sizeof USERNAME - 1;
but in this case USERNAME is not const char * const anymore, which is why I'm asking whether you really need it as such.
If you have to initialize a pointer for the literal, you can use the following:
const char un_str[] = "...", *un_ptr = un_str;
const size_t un_len = sizeof(un_str);
Note: sizeof() returns a size_t, which is unsigned.
You can pack that into a macro:
#define STR_LEN_PAIR(name, value) const char name##_str[] = value; \
const size_t name##_len = sizeof(name##_str)
This uses argument concatenation. Note the missing ; after the last line which allows to use standard syntax on invocation. Be careful to use it only as intended:
// at file level
STR_LEN_PAIR(un,"...");
The fields can be accessed like un_len, un_str, ...
Note that the pointer itself is not const, so there is not much use in it (you quite likely do not want to have a modifyable pointer to each such string). You can simply omit its definitions as I already did in the *macro.
Compatibility note:
C differs in the semantics of const. Actually, C does not have "constants" as C++ has. objects defined as const are actually "unmodifyable variables": they can only be initialized at compiler-time, but they consume space as any other variable (however, they might be located in unchangeable memory) and the compiler will generate read accesses as for any other variable. In C++, un_len for instance will be replaced by its value at compile-time and might consume no memory in the final program - as long as its address is not taken.
What comes next to real constants in C are either enum constants, or `#define'ed names. The latter are processed at a very different level (textual replacement by the pre-processor), however.
Related
I have two arrays of the alphabet in the following format:
const char plain[26] = {'a','b',....'y','z'} // this is the the full alphabet
const char crypt[26] = {'i','d',....'m','x'}; // this is the the alphabet scrambled
The order of the alphabet in both arrays can change depending on input. This change happens in the main function.
The purpose of this is to match the letters of the string to the second, like an encryption. I compare characters to array values. So it would kind of look like this (simplified)
text[3] = 'yes';
changed[3];
if(text[0] == plain[25]){ //would be done under a for loop so 25 would be a changing integer value
changed[0] = [crypt[25];
}
My code works under perfectly under the main function. I wanted to mention my purpose like this because I was having previous problems simply due to the type of array and formatting. And since the array is moved outside, I will probably/am running into those problems again.
Now I want to make the arrays global. The actual encryption happens in a function that does not take the arrays as a variable. But I want the function to have access to them.
Here's what it looks likes right now
const char plain[26];
const char crypt[26];
int maint(void){
const char plain[26] = {'a','b',....'y','z'} \\values get changed here
const char crypt[26] = {'i','d',....'m','x'} \\and here
While this provides no errors, I dont get an output, I believe the other functions are using a blank array instead of the changed one (if the change even worked).
I've tried different array types, I believe the issue is in initialization or giving the array values.
Edit: To clarify, the two arrays can be in any order. A text file will randomize the order can give it to me in the format:
b,r
m,o
l,s
...
...
...
Both cases the alphabet is randomized. Where the first column would correspond to the first array (plain), second would be to second array (crypt).
If there's a way to read by columns and store in the format
plain = 'bml...'; \\whole alphabet randomized
crypt = 'ros...'; \\whole alphabet randomized
That would also work.
The plain and crypt you have in main aren't the same as the global ones. Since you declare them again, they're new ones that are only visible in main. Thus you're not changing the global ones.
Instead, only declare them once globally and do assignment in the main function:
char plain[26];
int main(void) {
memcpy(plain, "abcdefghijklmnopqrstuvwxyz", 26); //values get changed here
return 0; // indicate successful program execution
}
Also note that there are some syntax errors in
const char plain[26] = {'a','b',....'y','z'} \\values get changed here
Comments start with //, not \\, and you need a ; after a statement. Also, the int main should return an int in C.
Of course, if you don't need to actually change the memory and only assign it to predefined sets of characters, you can do it like this:
const char *plain;
int main(void) {
plain = "abcdefghijklmnopqrstuvwxyz";
return 0;
}
This way you can still read from it with syntax like plain[5], but you can't assign to it with, say plain[5] = 'a';.
Remove "const char" before plain and crypt arrays in main function to see the actual issue.
“Const Char” before plan and crypt arrays actually declare two new local char array constants with same name. As “const” char array can only be initialized at the declaration time therefore initialization in main does not throw error because they are not same global conts arrays.
Instead of using const use Const pointer as suggested in below answer
Another way to look at it is that plain and crypt will both decay to pointers on access (subject to the exceptions in) C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). So why not just use global pointers to begin with that can then be reassigned as needed throughout your code?
This provides the flexibility of assignment from (1) string literals; (2) constant arrays; or (3) from compound literal initializers. You can #define a constant for the size (number of characters) plain and crypt point to.
For example:
#include <stdio.h>
#define NC 3 /* number of chars (26 for you) */
const char *plain, *crypt; /* global pointers */
void prnchars (const char *arr)
{
for (int i = 0; i < NC; i++)
putchar (arr[i]);
putchar ('\n');
}
int main (void) {
plain = "abc"; /* assigning literals */
crypt = "def";
prnchars (plain);
prnchars (crypt);
crypt = "ghi"; /* reassign at will */
prnchars (crypt);
const char foo[] = "jkl"; /* constant arrays */
crypt = foo;
prnchars (crypt);
crypt = (const char[]){'m', 'n', 'o'}; /* compound literals */
prnchars (crypt);
return 0;
}
Example Use/Output
$ ./bin/global_ptr
abc
def
ghi
jkl
mno
It's just another way of looking at the problem.
I need to define some strings and an array initialized with those strings available to use by different pieces of the software. I thought in defining them in a header file like this:
//.h file
const char *serviceStateKindNormal = "Normal";
const char *serviceStateKindUnmanned = "Unmanned";
const char *serviceStateKindScheduledMaintenanceDown = "ScheduledMaintenance (down)";
const char *serviceStateKindScheduledMaintenanceAvailable = "ScheduledMaintenance (available)";
const char *serviceStateKindMajorIncidentInProgress = "MajorIncidentInProgress";
const char *serviceStateKindPartialService = "PartialService";
const char *serviceStateKindOverloaded = "Overloaded";
const char *serviceStateKindGoingDown = "GoingDown";
const char *serviceStateKindDown = "Down";
const char *serviceStateKind[9] = {
serviceStateKindNormal,
serviceStateKindUnmanned,
serviceStateKindScheduledMaintenanceDown,
serviceStateKindScheduledMaintenanceAvailable,
serviceStateKindMajorIncidentInProgress,
serviceStateKindPartialService,
serviceStateKindOverloaded,
serviceStateKindGoingDown,
serviceStateKindDown
};
but the compiler shows
error: initializer element is not constant
serviceStateKindNormal
what exactly is the problem here and what choices do I have to define my variables?
Everything you put in an intialized of a variable that is declared at file scope must be a constant expression or a string literal, from initialization. There is a list what is a constant expression and variable value is not among them. So:
// there is an array of char[2]{'a',\0'} somewhere in the memory
// we store the pointer value to that array inside the variable a
static const char *a = "a";
// now we want to statically initialize variable b with the same value
static const char *b = a;
will not work, because b is initialized with the pointer a value, which is not a constant expression. You need a constant expression when initializing a variable with static storage duration.
What can you do? The following:
The good way: Why do you store the pointers to the string literals "Normal"? Why not store the data itself inside the array? Happily, variable address is a constant expression, so we can use it in initialization! Note that (almost) all use cases and semantics stay the same, except for some corner usage like sizeof(serviceStateKindNormal) operator results.
const char serviceStateKindNormal[] = "Normal";
const char serviceStateKindUnmanned[] = "Unmanned";
const char *serviceStateKind[] = {
serviceStateKindNormal,
serviceStateKindUnmanned,
};
A strange way: store the pointers to the pointers to strings inside the array. As variable addresses are constant expressions, this will work. Note that makes the serviceStateKind a three star variable. You need to double dereference the array on usage. The serviceStateKind is an array of pointers of pointers to strings. Note that it is very confusing on how to use such array, so I suggest you go with a structure then.
const char *serviceStateKindNormal = "Normal";
const char *serviceStateKindUnmanned = "Unmanned";
const char **serviceStateKind[] = {
&serviceStateKindNormal,
&serviceStateKindUnmanned,
};
int main() {
// question which one is correct?
printf("%s\n", *serviceStateKind[1]);
printf("%s\n", (*serviceStateKind)[1]);
printf("%s\n", serviceStateKind[0][1]);
}
but as i don't think of myself as a three star programmer, I would try to make it at least to two stars:
const char *serviceStateKindNormal = "Normal";
const char *serviceStateKindUnmanned = "Unmanned";
struct {
// points to a string
const char **pnt;
// an array of pointers to string
} serviceStateKind[] = {
&serviceStateKindNormal,
&serviceStateKindUnmanned,
};
int main() {
// more verbose
printf("%s\n", *serviceStateKind[0].pnt);
}
The old fashioned way - macros. Don't do it. And what is bad about it, you can abuse preprocessor concatenation of string literals, to concatenate them together.
#define serviceStateKindNormal "Normal"
#define serviceStateKindUnmanned "Unmanned"
const char *serviceStateKind[] = {
serviceStateKindNormal,
serviceStateKindUnmanned,
};
int main() {
# magic
printf(serviceStateKindNormal " " serviceStateKindUnmanned "\n");
}
I thought in defining them in a header file like this:
If you are defining the variables in a header file, you want to mark them with static, so that you will not get duplicate symbol errors on linking with different .c files that use that .h file. Also it's nice to mark the variable as const as a hint to other programmers that they are somewhat not changable.
In C language constant refers to literal constants, like (3.14, 2.718, etc).
Const-qualified objects (of any type) are not constants in C language terminology.
For creating constants in C language terminology use #define directive, for example:
#define ServiceStateKindNormal "Normal"
etc.
with this list of value:
char *icon[6] = {"icon0","icon1","icon2","icon3","icon4","icon5"};
char *ICON_FILE_PATH[6] = {"host0:img/200px/power-button-off.png","host0:img/200px/gamepad-console.png","host0:img/200px/dropbox-logo.png","host0:img/200px/open-folder.png","host0:img/200px/sitemap.png","host0:img/200px/settings.png"};
I need to get that:
#define ICON_FILE_PATH1 "host0:img/200px/power-button-off.png"
#define ICON_FILE_PATH2 "host0:img/200px/gamepad-console.png"
etc...
extern Orbis2dTexture *icon0;
extern Orbis2dTexture *icon0;
etc...
Orbis2dTexture *icon0 = NULL;
Orbis2dTexture *icon0 = NULL;
etc...
for each value of ICON_FILE_PATH.
I mean to use :
for (int i=0; i<=5; i++ )
{
#define ?????
extern ?????
Orbis2dTexture ????
}
But I don't know how do...
If you want strings change 'to ".
char *icon[6] = {"icon0","icon1","icon2","icon3","icon4","icon5"};
That sets up an array of pointers to char, initialised with the "readonly" pointers to string literals.
'icon0' is a (weird) multibyte character constant, not a multi character constant which could serve as a string.
The rest of the shown code is even more weird. I skip discussing it here.
Have a look at the comments.
Allow me to recommend starting with HelloWorlds and tutorials which provide you with known good code and then do little steps, always verified by testing, to upgrade the functionality of your program and your knowledge in parallel.
What I want to do is have string256 act like: char* s = (char*)malloc(256);
string256 s; /* this is what Iam trying to do */
char* s = (char*) malloc(256); /* this is how it looks in real life */
and use it
strncpy(s, "__test__", 9)
s[9] = 0x00;
P.s. typedef or define or function code length doesn't matter. only matters string256 s;
I won't forget to use free or error checking;
full code will look like this :
__Free_String_if_Flag_true __Zero_Memory __check_for_Errors __string_256 string256
and use it
string256 s;
You can make a typedef of a char array:
typedef char char256[256];
char256 s ;
s[255] = '\0' ;
The variable will stop existing when out of scope, but you can make it global if you want it persistent.
In short, no.
A typedef defines a name for a type. char* s = (char*) malloc(256); is a variable declaration, not a type.
You could probably achieve something similar with macros, but I would strongly advise against it (for a start, it would obscure the fact that a free would be necessary at some point.)
As for the part of your question asking about ...or define...:
In short - Yes you can: (partially taking exception with some of the other comments/answers)
However, I also agree with those answers that suggest it may not be in the best form to use #defines for such calls. (but you can do it)
Edited (removed ";" from macro)
#define string256(s) char *(s) = malloc(256)
//...
string256(s); //use parenethesis
/...
strcpy(s, "yes I can");
s now contains "yes I can" and is null terminated (strcpy() does that)
Do not forget to also create a macro for free(...);
I'm trying to initialize an array of strings in C. I want to set one of the elements of the array from a variable, but I'm getting a compiler error. What's wrong with this?
char * const APP_NAME = "test_app";
char * const array_of_strings[4] = {
APP_NAME,
"-f", "/path/to/file.txt",
NULL
};
The error is error: initializer element is not constant.
The standard distinguishes const-qualified variables and compile time constants.
Evaluating a variable (APP_NAME) is not considered to be a compile time constant in the sense of the C standard. This
char const app_name[] = "test_app";
char const*const array_of_strings[4] = {
&app_name[0],
"-f", "/path/to/file.txt",
0,
};
would be allowed, since this is not evaluating app_name but only taking its address.
Also, you always should treat string literals as if they had type char const[]. Modifying them has undefined behavior, so you should protect yourself from doing so.
I was able to get it to compile with this syntax using gcc 4.6.3:
char* const APP_NAME = "test_app";
char* const array_of_strings[4] = {
APP_NAME,
"-f", "/path/to/file.txt",
NULL
};
You could also try casting to a const (at your own risk) if the compiler rejects everything else:
char* const APP_NAME = "test_app";
char* const array_of_strings[4] = {
(char* const)APP_NAME,
"-f", "/path/to/file.txt",
NULL
};