Today I got some information that we can get the offset of a field in structure this way:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
struct sdshdr {
int len;
int free;
};
int main(int argc, char* argv[])
{
printf("%d\n", &sdshdr::len);
printf("%d\n", &sdshdr::free);
}
Although I got warnings at compile time, it can successfully run.
How can we explain this? I didn't get information when I searched the web.
Can anyone help explain what happened here?
compilation arguments: gcc -g -O2 -Wall -o main.o main.cpp
Code you showed is not a C-compliant code. These constructions
&sdshdr::len and &sdshdr::free are not valid C constructions.
It seems you compiled the code as a C++ code.
If you want to know the offset of a data member of a structure in C then you should use standard macro offsetof declared in header <stddef.h>
For example
#include <stdio.h>
#include <stddef.h>
struct sdshdr {
int len;
int free;
};
int main(void)
{
printf( "offset of len is equal to %zu\n", offsetof( struct sdshdr, len ) );
printf( "offset of free is equal to %zu\n", offsetof( struct sdshdr, free ) );
return 0;
}
The program output might look like
offset of len is equal to 0
offset of free is equal to 4
If you mean C++ then these expressions
&sdshdr::lenand&sdshdr::free` denote pointers to data members within the structure.
Related
I wrote a small piece of code to understand how the offsetof macro works in the background. Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
/* Getting the offset of a variable inside a struct */
typedef struct {
int a;
char b[23];
float c;
} MyStructType;
unsigned offset = (unsigned)(&((MyStructType * )NULL)->c);
printf("offset = %u\n", offset);
return 0;
}
However, if I run it I get a warning message:
WARNING: cast from pointer to integer of different size [-Wpointer-to-int-cast]
However, if I look at the original offsetof macro in c, the code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(void)
{
/* Getting the offset of a variable inside a struct */
typedef struct {
int a;
char b[23];
float c;
} MyStructType;
unsigned offset = offsetof(MyStructType, c);
printf("offset = %u\n", offset);
return 0;
}
So why do I get the warning as I cast to unsigned ? It appears to be the type for the offsetof macro. This is puzzling me.
As mch commented, unsigned is not the right type; it's 32-bit on pretty much all real-world systems. The offsetof macro is supposed to produce a result of type size_t, which is what you "should" be casting to here. I think you're confused by the code you found storing the result into an object of type unsigned; that's okay as long as they're sure the value is small, but it doesn't mean the type of the expression offsetof(MyStructType, c); was unsigned. C allows you to silently assign a larger integer type into a smaller one.
However, no matter what you do, this is not a valid implementation of offsetof and has undefined behavior (via applying -> to an invalid pointer). The way you get a working offsetof without UB is #include <stddef.h>.
I am trying the following, with gcc on win32.
#include <stdio.h>
struct st { char c; int x; } __attribute__ ((packed));
int main() {
printf("%d\n", sizeof(struct st));
return 0;
}
I would expect that the printed value is 5, but it's 8.
With the following, however, I get 5.
#include <stdio.h>
#pragma pack(1)
struct st { char c; int x; };
int main() {
printf("%d\n", sizeof(struct st));
return 0;
}
There must be something wrong in my program, but I can't see what.
I have read gcc's manual and several questions on SO about this, and I'm still puzzled. Any hint?
Also from the answers to these questions on SO, I understand that I should not use packed structs for marshalling, and I probably won't use it much, but I still would like to understand what I'm not able to see in such a short program.
Note: the problem occurs with both gcc-4.9.2 and gcc-4.8.4.
You have the attribute in the wrong place - try this:
struct st { char c;
int x __attribute__ ((packed));
};
As per the example in the gcc manual, this will cause x to be packed such that it immediately follows c.
Of course you shouldn't really be doing this in the first place, as your code will break on certain architectures, and even where it doesn't break there may be performance penalties.
Working fine on my environment Centos 5.11 (64bit)
prints 5 for the first case you mentioned.
gcc version 4.9.1 (GCC)
gcc file.c
./a.out
5
I want to be able to reference variable sized array with a global pointer. But what kind of pointer do I use that will work with variable sizes of the array? In the example below, assume N will only be known at runtime (could be an argument for example) so compile time solutions won't work.
What I want to achieve:
main.c
some_sort_of_pointer *x;
main()
{
int N=256; //or N=64 or whatever
char (*LC)[N];
LC=malloc(1024);
x=LC;
memcpy(x[2],"hello world",11);
x[0][176]=123;
dostuff();
}
I'm sure there's an easy obvious way to do this but I can't seem to nail it. My first attempt at asking this was a mess so this time I'm hoping it's clear what I want to achieve.
OS Centos 6.5
compiler GCC 4.8 (using C99)
As at compile time the type to be referenced isn't given, a void pointer might help.
However only storing an untyped reference (what void * in fact is is) is not enough, as it is essential to also know the size of the (VL)array. So the latter also needs to be stored globally, as it can not be pulled from the memory referenced.
An example how this can be achieve is given below:
main.h:
#include <stdlib.h> /* for size_t */
struct VLA_descriptor
{
void * p;
size_t s;
}
extern struct VLA_descriptor vla_descriptor;
foo.h:
void foo(void);
foo.c:
#include "main.h"
#include "foo.h
void foo(void)
{
char (*p)[vla_descriptor.s] = vla_descriptor.p;
/* Do something with the VLA reference p. */
}
main.c:
#include "main.h"
#include "foo.h"
struct VLA_descriptor vla_descriptor = {0};
int main(int argc, char ** argv)
{
size_t s = atoi(argv[1]);
char (*p)[s] = malloc(s);
vla_descriptor.p = p;
vla_descriptor.s = s;
foo();
... /* Free stuff and return. */
}
Error checking had been omitted in this example's code for the sake of readability.
With much thanks to #alk (and everyone else who responded) I think I have the closest I'm going to get to what I'm looking for:
void *LC
int LCS;
int main(int argc, char **argv) {
LCS=256;
LC=malloc(1024)
memcpy(((char(*)[LCS])LC)[2],"hello world",11);
((char(*)[LCS])LC)[0][176]=123;
printf("%d %s\n",((char(*)[LCS])LC)[0][176],&((char(*)[LCS])LC)[2]);
}
((char(*)[LCS])LC) is the equivalent of a what I wanted. It's similar to #alk's idea and does require 2 globals but it means I can use it in functions without having to declare a new variable. I've credited #alk with the answer as what he posted gave me 90% of what I needed.
Though if anyone can reduce ((char(*)[LCS])LC) to a single global, I would be excited to see it :)
First of all I know that array A degrades to pointer when we call function f(int a[]) and f(int *p) is same.
BUT:
1.I really need sending by value all array.
2.I really need that sending size is non const in function (but const size in plase we calling function)
I write some example:
http://ideone.com/ZbW0wT
#include <stdio.h>
#define SZ 15
typedef struct {int a[SZ];} rec;
int main(){
void pa(rec);
int value[SZ] ={9,8,7,6,5,4,3,2,1,0};
pa(*(rec*)value);
printf("%u %u\n",sizeof(rec),sizeof(value));
return 0;
}
void
pa(rec b){
int z;
for(z=0;z<SZ;z++){
printf("array[%2d] is %d\n",z,b.a[z]);
}
}
This code work for const size , but how change so pa would get by value some rec which size depend on passed array?
Update: it must by value sended , but not const sized as in Pascal etc , but in true C way , all pass by value not by pointer on 0 element
and function need universal so user can write func(variablesizeArrayOfT) where arg passed by value.
if possible need standard way (C11 or better C99 or better C89 or better K&R), if cant then gcc
UPD2: http://ideone.com/H4XGqC
#include
typedef struct{
int len;
int a[];
} av;
void f(av a){
while(a.len--){
printf("array[%2d] is %d\n",a.len,a.a[a.len]);
}
}
int main(){
int b[]={3,1,2,3};
int c[]={7,1,2,3,4,5,6,7};
f(*(av*)b);
f(*(av*)c);
return 0;
}
all good by probably bug in alignment so size(3 and 7) is right but value of a[] is not
UPD3 see throw gcc -g -c 2ndSRC.c &&objdump -d -M intel -S 2ndSRC.o
it just send only size (b[0] and c[0]) but not all array
An idiomatic way to have arrays containing data of variable length in C is to use a buffer with a maximum size which is known at compile time, is that what you wanted?
#include <stdio.h>
#define MAX_SIZE 15
typedef struct {
int arr[MAX_SIZE];
size_t arr_len;
} rec_t;
void pa(rec_t rec){
for(int z=0; z<rec.arr_len; z++){
printf("array[%2d] is %d\n", z, rec.arr[z]);
}
}
int main(void){
rec_t rec ={
.arr = {9,8,7,6,5,4,3,2,1,0},
.arr_len = 10
};
pa(rec);
}
When I compile the following code:
#define _POSIX_C_SOURCE 200112L
#define _ISOC99_SOURCE
#define __EXTENSIONS__
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
char *symlinkpath = argv[1];
char actualpath [PATH_MAX];
char *ptr;
ptr = realpath(symlinkpath, actualpath);
printf("%s\n", ptr);
}
I get a warning on the line that contains the call to the realpath function, saying:
warning: assignment makes pointer from integer without a cast
Anybody know what's up? I'm running Ubuntu Linux 9.04
This is very simple. Glibc treats realpath() as a GNU extension, not POSIX. So, add this line:
#define _GNU_SOURCE
... prior to including stdlib.h so that it is prototyped and known to to return char *. Otherwise, gcc is going to assume it returns the default type of int. The prototype in stdlib.h is not seen unless _GNU_SOURCE is defined.
The following complies fine without warnings with -Wall passed:
#include <stdio.h>
#include <limits.h>
#define _GNU_SOURCE
#include <stdlib.h>
int
main(int argc, char *argv[])
{
char *symlinkpath = argv[1];
char actualpath [PATH_MAX];
char *ptr;
ptr = realpath(symlinkpath, actualpath);
printf("%s\n", ptr);
return 0;
}
You will see similar behavior with other popular extensions such as asprintf(). Its worth a look at /usr/include/ to see exactly how much that macro turns on and what it changes.
The compiler doesn't know what realpath is, so it assumes it's a function returning int. It does this for historical reasons: a lot of older C programs relied on it doing this.
You're probably missing the declaration of it, e.g. by forgetting to #include its header file.