I am getting an error message "expression must have constant value" when initializing an array of structures with an external constant integer.
File1.c:
const unsigned char data1[] =
{
0x65, 0xF0, 0xA8, 0x5F, 0x5F,
0x5F, 0x5F, 0x31, 0x32, 0x2E,
0x31, 0xF1, 0x63, 0x4D, 0x43,
0x52, 0x45, 0x41, 0x54, 0x45,
0x44, 0x20, 0x42, 0x59, 0x3A,
0x20, 0x69, 0x73, 0x70, 0x56,
// ...
};
const unsigned int data1_size = sizeof(data1);
File2.c:
const unsigned char data2[] =
{
0x20, 0x44, 0x61, 0x74, 0x61,
0x20, 0x52, 0x6F, 0x77, 0x20,
0x3D, 0x20, 0x34, 0x38, 0x12,
//...
};
const unsigned int data2_size = sizeof(data2);
Get_Byte.c:
extern const unsigned char * data1;
extern const unsigned int data1_size;
extern const unsigned char * data2;
extern const unsigned int data2_size;
struct Array_Attributes
{
const unsigned char * p_data;
const unsigned int size;
};
const struct Array_Attributes Data_Arrays[] =
{
{data1, data1_size}, // Error message is for data1_size here.
{data2, data2_size}, // Another error message generated for data2_size here.
};
I have also removed the const qualifier from the size field of Array_Attributes and get the same error message.
Why is the compiler complaining about a constant value expression when data1_size and data2_size are const unsigned int but in a different translation unit?
I want a constant array of [array address, array size] which is generated at compile time.
I am using Green Hills ccarm 4.24, on Windows XP, C language NOT C++.
C's const qualifier has little to do with what the compiler considers a constant expression, in this case. In an initializer, ie
const struct attributes attrs[] = {
{ expr1, expr2 },
...
}
expr1 and expr2 must have very specific forms to be acceptable to the compiler. The upshot of these restrictions is that the expressions can be evaluated without fetching from program variables, since these aren't in existence at compilation.
You're attempting to use data1_size and data2_size, which are not compile time constants by these rules.
By the way, the declarations
const unsigned char data1[] = { ... };
and
extern const unsigned char *data1;
are not compatible and will lead to a bug in your code. The latter should be
extern const unsigned char data1[];
Related
In Libtomcrypt crypto library, AES encryption/decryption are implemented in two different way .
Use of lookup table of size 8KB (encryption)/5KB (decryption).
Use of lookup table of size 2KB (encryption)/2KB (decryption). In this case LTC_SMALL_CODE is true.
This is the source code of aes_tab.c and aes.c.
#ifdef LTC_SMALL_CODE
#define Te0(x) TE0[x]
#define Te1(x) RORc(TE0[x], 8)
#define Te2(x) RORc(TE0[x], 16)
#define Te3(x) RORc(TE0[x], 24)
#define Td0(x) TD0[x]
#define Td1(x) RORc(TD0[x], 8)
#define Td2(x) RORc(TD0[x], 16)
#define Td3(x) RORc(TD0[x], 24)
#define Te4_0 0x000000FF & Te4
#define Te4_1 0x0000FF00 & Te4
#define Te4_2 0x00FF0000 & Te4
#define Te4_3 0xFF000000 & Te4
#else
#define Te0(x) TE0[x]
#define Te1(x) TE1[x]
#define Te2(x) TE2[x]
#define Te3(x) TE3[x]
#define Td0(x) TD0[x]
#define Td1(x) TD1[x]
#define Td2(x) TD2[x]
#define Td3(x) TD3[x]
#endif /* ENCRYPT_ONLY */
#endif /* SMALL CODE */
The following C code performs AES encryption and decryption using libtomcrypt crypto library.
However, the code invokes AES implementation that uses 8KB/5KB lookup table
(means LTC_SMALL_CODE condition becomes false).
//aes_tom_example.c
#include <tomcrypt.h>
static const unsigned char key[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
int main()
{
unsigned char text[]="hello world!";
unsigned char enc_out[80];
unsigned char dec_out[80];
symmetric_key skey;
int keysize = 32;
int status;
status = aes_keysize(&keysize);
status = aes_setup(key, 32, 0, &skey);
status = aes_ecb_encrypt(text,enc_out,&skey);
status = aes_ecb_decrypt(enc_out, dec_out, &skey);
int i;
printf("original:\t");
for(i=0;*(text+i)!=0x00;i++)
printf("%c ",*(text+i));
printf("\nencrypted:\t");
for(i=0;*(enc_out+i)!=0x00;i++)
printf("%X ",*(enc_out+i));
printf("\ndecrypted:\t");
for(i=0;*(dec_out+i)!=0x00;i++)
printf("%c ",*(dec_out+i));
printf("\n");
return 0;
}
Compile and run as below ,
gcc aes_tom_example.c -o aes -ltomcrypt
./aes
Sample Output
original: h e l l o w o r l d !
encrypted: AE 21 D5 A5 5E D5 F1 EF 6D FC E5 30 60 34 3D 12
decrypted: h e l l o w o r l d !
My questions are:
How to modify this C code so that it invokes the #ifdef LTC_SMALL_CODE condition part (means 2KB lookup table based implementation code invoked )?
How to run the above code with LTC_SMALL_CODE condition true?
Do I need some parameter before calling SETUP (aes_setup) function ? Or Do I need to pass some parameters at the time of compilation/run time?
It would be great if anyone can provide some link or sample code.
I am using Ubuntu 16.04 / Debian 8. gcc v-4.9.
In the following project, the necessary parameters to initialize test.c are arranged in the structure DataStructure (Here I have only a pointer U8* Buffer). During init, the pointer Buffer is initialized (is pointed to an array) and the function test_init passes the initData to test.c. In test.c the content of the array is printed.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
void init(DataStructure *pSL);
void main(void);
void main(void) {
DataStructure initData[COUNT];
init(&initData[0]);
test_init(&initData[0]);
test_run();
}
void init(DataStructure *pSL)
{
U8 Buffer[8] = {0xF1 , 0xF2 , 0xF3 , 0xF4 , 0xF5 , 0xF6 , 0xF7 , 0xF8};
DataStructure SL;
U8* pC = &Buffer[0];
SL.Buffer = pC;
*pSL = SL;
}
where test.c and test.h are:
#ifndef TEST_H_
#define TEST_H_
#ifndef U8
typedef unsigned char U8;
#endif
typedef struct{
U8 *Buffer;
} DataStructure;
#define COUNT 1
void test_init (DataStructure *List);
void test_run ();
#endif /* TEST_H_ */
and
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
static DataStructure *pD;
void test_init (DataStructure *_pD)
{
pD = _pD;
printf("\n test_init: ");
for(int i=0;i<8;i++)
printf("0x%0x, ",*(pD->Buffer+i));
}
void test_run (void)
{
printf("\n test_run: ");
for(int i=0;i<8;i++)
printf("0x%0x, ",*(pD->Buffer+i));
}
The output of this code is:
test_init: 0x0, 0x0, 0x0, 0x0, 0xf5, 0xf6, 0xf7, 0xf8,
test_run: 0x0, 0x0, 0x0, 0x0, 0xf5, 0xf6, 0xf7, 0xf8,
which is wrong. But if I print the elements of SL.Buffer within init function as well, i.e if I change the init function as follows:
void init(DataStructure *pSL)
{
U8 Buffer[8] = {0xF1 , 0xF2 , 0xF3 , 0xF4 , 0xF5 , 0xF6 , 0xF7 , 0xF8};
DataStructure SL;
U8* pC = &Buffer[0];
SL.Buffer = pC;
*pSL = SL;
printf("\n main: ");
for(int i=0;i<8;i++)
printf("0x%0x, ",*(SL.Buffer+i));
}
, the array is passed correctly:
main: 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
test_init: 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
test_run: 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
Could anybody explain me whats wrong whit this code and why the problem is fixed just by printing the array in init function?
And is it the right way to initialize and pass a structure containing a pointer?
The code is a simple version of my project. Originaly the DataStructure contains more parameters and the parameter COUNT (size of initData is more than one.
The problem, as I see it is with the usage of Buffer array.
It is local to the init() function, yet you return the address of the first element of the array to be used outside the function, where the array does not exist anymore. Hence, the address is essentially invalid and any attempt to access that memory will cause undefined behavior.
In the second case, it works fine, as you're printing the array before it ceases it's lifetime, so you're getting expected result.
Solution: You need to allocate static storage to the Buffer array, or use memory allocator function so as, the lifetime of the memory supersede the function scope.
typedef struct BO2Offsets
{
struct Prestige
{
u32 offset = 0x000000;
char data[13] = { 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09,
0x0A, 0x0B, 0x0C
};
};
} BO2Offsets;
This is a very amateur question with what I'm sure is going to be a very simple answer, but I can't resolve the problem. I have a .h file with his corresponding .cpp file, but for some reason whenever I try to compile with gcc, I keep getting errors:
declaration does not declare anything // line 10
expected ':', ',', ';', '}' or 'attribute' before '=' token // line 5
I would like use BO2Offsets like that:
BO2Offsets BO2;
BO2.Prestige.offset;
EDIT2:
Resolved, thank's :)
typedef struct BO2Offsets BO2Offsets;
struct BO2Offsets
{
struct Prestige
{
u32 offset;
char data[13];
} prestige;
};
You are probably using C compiler, but the code is C++ (that too C++14). You need to change the compiler (or toolset), or change the code so that it compiles with C compiler.
EDIT: Which line? Does it say struct Prestige is not utilized?
Based on your edit:
typedef struct Prestige
{
u32 offset = 0x000000;
char data[13] = { 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09,
0x0A, 0x0B, 0x0C
};
} prestige; // Small letters
...
BO2Offsets BO2;
BO2.prestige.offset;
I've used small letters for the variable, so that it is clearly different from the type Prestige.
When I run the following code
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
const uint8_t Symbols[] = {
0xCA,0x04,// size
0x0B, // width
0x0B, // height
0x00, // first char
0x04, // char count
0x01, 0x02, 0x03, 0x04,// char widths
// font data
0x00, 0x00, 0x20, 0x00, 0xF0, 0x07, 0x08, 0x04, 0x84, 0x07, 0x84, 0x07, 0x84, 0x07, 0x0E, 0x04, 0xF0, 0x07, 0x20, 0x00, 0x00, 0x00, // 0
0x10, 0x01, 0x08, 0x01, 0x04, 0x01, 0x04, 0x01, 0x08, 0x01, 0x10, 0x01, 0x10, 0x01, 0x08, 0x01, 0x04, 0x01, 0x04, 0x01, 0x00, 0x00, // 1
0x18, 0x00, 0xFF, 0x07, 0x18, 0x00, 0x00, 0x00, 0x80, 0x01, 0xFF, 0x07, 0x80, 0x01, 0x00, 0x00, 0x0C, 0x00, 0xFF, 0x07, 0x0C, 0x00, // 2
0x00, 0x02, 0x80, 0x05, 0x60, 0x04, 0x18, 0x04, 0x04, 0x04, 0x72, 0x05, 0x04, 0x04, 0x18, 0x04, 0x60, 0x04, 0x80, 0x05, 0x00, 0x02 // 3
};
typedef struct
{
uint16_t size; //2
uint8_t width; //1
uint8_t height; //1
uint8_t first_char; //1
uint8_t char_count; //1
uint8_t *font_widths;
uint8_t *font_data;
} _graphics_font;
_graphics_font* test;
uint8_t* font_st;
uint8_t temp;
int main(void)
{
test = (_graphics_font*)&Symbols;
font_st = (uint8_t*)&test->font_widths;
temp = font_st[0]+font_st[1]+font_st[2]+font_st[3]; //1+2+3+4 = 10
printf("temp=%d",temp);
return 0;
}
in C, I'm expecting that the pointer font_st will point exactly after the 6-th Byte of the Symbols array. Therefore the result printed should be 10. Instead of that the pointer is allocated to the 9-th byte, missing every time 2 bytes and wrongly to my expectations is printing 7 as a result. Why and how could that be?
Important update is that the using instead the line:
temp = font_st[-2]+font_st[-1]+font_st[0]+font_st[1]; //1+2+3+4 = 10
works.
This behaviour is most likely caused by struct padding.
Try the following:
#include <stdio.h>
#pragma pack(push, 1)
.... (all other code)
#pragma pack(pop)
As to the location of single elements in a struct, read about padding and packing, e.g. Structure padding and packing.
You could try it like this:
typedef struct glyph {
uint8_t char_width;
uint8_t[] glyph_data;
} glyph_t;
typedef struct font_t {
uint16_t size; //2
uint8_t width; //1
...
glyph_t[] glyphs;
} font_t;
That way, you can avoid some issues you are facing due to the dynamic addresses of the data, i.e. those which depend on the value of char_count.
Of course, if the size of glyph_data is not a constant, you have to provide your own access logic, like
uint8_t* p_glyph = (uint8_t*)(font->glyph_data[0]);
for ( int i = 0; i < requiredCharIndex; i++ ) {
p_glyph += total_size_of_glyph_in_bytes( (glyph_t*)p_glyph );
}
glyph_t* result = (glyph_t*)p_glyph;
test = (_graphics_font*)Symbols;
font_st = (uint8_t*)test->font_widths;
I didn't check that, but at simple sight I would say that &s was wrong in that context. Symbols and test are already pointers, so you are referencing to the address to that pointers.
You are not initializing correctly the two pointers in your struct.
test = (_graphics_font*)&Symbols;
On this line you are copying byte by byte from Symbols to test, which means that font_widths will point to the address made up by combining 0x01, 0x02, 0x03, 0x04, which contains garbage data.
Why 4 bytes? because every pointer in C has a size of 4 bytes regardless of the data it is pointing to.
Moreover, font_data will have the same behaviour.
Solution:
You have to use memcpy:
test->font_widths = (uint8_t*)memcpy(test->font_widths, Symbols + 6, 4*sizeof(uint8_t));
The same goes for font_data.
my USART is receiving a string from a "black box" and the string contains two doubles and few hex values. The string is placed in my buffer rbuf.buf with a total size of 32 characters. Normally I receive 19 characters but few times extra erroneous characters at the end. The buffer typically looks like this (in hex):
0x31, 0x32, 0x33, 0x2e, 0x34, 0x35, 0x20, 0x36, 0x37, 0x2e, 0x38, 0x39, 0x20, 0x37, 0x41, 0x41, 0x20, 0x0a, 0x0d, 0x00, ...
I want to extract the two doubles 123.45 and 67.89 and have among several other examples tried following:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
...
void buffer_to_float(void)
{
static char string1[10] = "";
char *string2;
for(uint8_t i=0;i<6;i++)
{
char c = rbuf.buf[i]; // this is a char but how do I make it a pointer?
string2 = strcat ( string1, c ); // ... "char" is incompatible with "char*" ...
}
double R = atof(string2);
printf("%lf\n", R);
}
I know I'm doing something silly here but what?
I use an interrupt routine for receiving the string, should I do the extraction there or should this routine be as short/quick as possible?
Thanks for telling me how silly I am, I think I need it ;-)
You can use the sscanf function to read your two float values:
char bla[] = {0x31, 0x32, 0x33, 0x2e,
0x34, 0x35, 0x20, 0x36,
0x37, 0x2e, 0x38, 0x39,
0x20, 0x37, 0x41, 0x41,
0x20, 0x0a, 0x0d, 0x00};
float a, b;
sscanf(bla, "%f %f", &a, &b);
printf("%f %f\n", a, b);