Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

370
Vistas
¿Cómo puedo imprimir el desplazamiento de un miembro de estructura en tiempo de compilación?

Dada una estructura, por ejemplo:

 struct A { char a; char b; } __attribute__((packed));

Quiero que el desplazamiento de b (en este ejemplo, 1) en la estructura se imprima en tiempo de compilación. No quiero tener que ejecutar el programa y llamar a algo como printf("%zu", offsetof(struct A, b)); porque la impresión no es trivial en mi plataforma. Quiero que el propio compilador imprima el desplazamiento, algo así como:

 > gcc main.c The offset of b is 1

Probé algunos enfoques usando #pragma message y offsetof , siendo mi más cercano:

 #define OFFSET offsetof(struct A, b) #define XSTR(x) STR(x) #define STR(x) #x #pragma message "Offset: " XSTR(OFFSET)

que solo imprime:

 > gcc main.c main.c:12:9: note: #pragma message: Offset: __builtin_offsetof (struct A, b)

que no imprime el desplazamiento numérico. Es posible realizar una búsqueda binaria del desplazamiento en el momento de la compilación usando _Static_assert , pero mis estructuras reales son grandes y esto puede volverse un poco engorroso.

over 4 years ago · Santiago Trujillo
5 Respuestas
Responde la pregunta

0

Dada esta macro:

 #define PRINT_OFFSETOF(A, B) char (*__daniel_kleinstein_is_cool)[sizeof(char[offsetof(A, B)])] = 1

Úselo en su función main() (o cualquier función):

 struct Test { char x; long long y; int z; }; int main(void) { PRINT_OFFSETOF(struct Test, z); return 0; }

Y obtendrás esta advertencia:

 warning: initialization of 'char (*)[16]' from 'int' makes pointer from integer without a cast [-Wint-conversion]

Por lo tanto, offsetof(struct Test, z) == 16 .


NOTA: en caso de que offsetof() devuelva 0 (por ejemplo: PRINT_OFFSETOF(struct Test, x) ), la advertencia del compilador tendrá char (*)[] en lugar de char (*)[16] .

NOTA 2: Solo probé esto con GCC.

over 4 years ago · Santiago Trujillo Denunciar

0

Una forma posible es hacer que el desplazamiento sea del tamaño de una matriz y luego pasar la dirección de esa matriz a una función que espera un puntero incompatible para que imprima el tipo:

 static int a[offsetof(struct A, b)]; static void foo1(int *p) { (void)p; } static void foo2(void) { foo1(&a); }

Esto imprime:

 x1.c: In function 'foo2': x1.c:13:1: warning: passing argument 1 of 'foo1' from incompatible pointer type [enabled by default] static void foo2(void) { foo1(&a); } ^ x1.c:12:13: note: expected 'int *' but argument is of type 'int (*)[1]' static void foo1(int *p) { (void)p; } ^
over 4 years ago · Santiago Trujillo Denunciar

0

Tal vez sería aceptable un nuevo paso de preprocesamiento. Esto podría hacerse como un paso separado que no afectará su producción binaria.

offsetdumper.sh

 #!/bin/bash # # pre-process some source file(s), add a macro + main() and a file with rules # describing the interesting symbos. Compile and run the result. dumprulefile="$1" shift # Define your own macros, like OFFSET, in the "Here Document" below: { gcc -E "$@" && cat<<EOF #define OFFSET(x,y) do { printf("%s::%s %zu\n", #x, #y, offsetof(x,y)); } while(0) #include <stddef.h> #include <stdio.h> int main() { EOF cat "$dumprulefile" echo '}' } | g++ -xc - && ./a.out

rules

 OFFSET(A,a); OFFSET(A,b);

source.h

 typedef struct { char a; char b; } __attribute__((packed)) A;

Ejemplo:

 $ ./offsetdumper.sh rules *.h A::a 0 A::b 1

Esto es un poco frágil y no funcionará si su source.h incluye una función main , por lo que puede necesitar algunos retoques para satisfacer sus necesidades.

over 4 years ago · Santiago Trujillo Denunciar

0

Sorprendentemente, parece que __builtin_choose_expr funciona dentro del atributo de función __deprecated__ . El siguiente programa:

 #include <stddef.h> struct A { char a; char b; } __attribute__((packed)); #define printval_case(x, xstr, y, ...) __builtin_choose_expr(x == y, xstr"="#y, __VA_ARGS__) #define printval(x) do { \ __attribute__((__deprecated__( \ printval_case(x, #x, 0, \ printval_case(x, #x, 1, \ printval_case(x, #x, 2, \ printval_case(x, #x, 3, \ /* etc... */ \ (void)0 )))) \ ))) void printval() {} \ printval(); \ } while (0) int main() { printval(offsetof(struct A, a)); printval(offsetof(struct A, b)); }

Cuando se compila, entonces gcc generará:

 <source>:23:30: warning: 'printval' is deprecated: offsetof(struct A, a)=0 [-Wdeprecated-declarations] <source>:24:30: warning: 'printval' is deprecated: offsetof(struct A, b)=1 [-Wdeprecated-declarations]

De manera similar, podría incrustar el valor en el ejecutable (de manera similar a cómo CMake detecta cosas del compilador ):

 #include <stddef.h> struct A { char a; char b; } __attribute__((packed)); #define printval_case(x, xstr, y, ...) __builtin_choose_expr(x == y, xstr"="#y, __VA_ARGS__) #define embedval(x) do { \ static const __attribute__((__used__)) const char unused[] = \ printval_case(x, #x, 0, \ printval_case(x, #x, 1, \ printval_case(x, #x, 2, \ printval_case(x, #x, 3, \ /* etc... */ \ (void)0 )))); \ } while (0) int main() { embedval(offsetof(struct A, a)); embedval(offsetof(struct A, b)); }

luego:

 $ gcc file.c && strings ./a.out | grep offsetof offsetof(struct A, b)=1 offsetof(struct A, a)=0
over 4 years ago · Santiago Trujillo Denunciar

0

Sospecho que la restricción establecida "Quiero que el compilador imprima el desplazamiento" es un problema XY y que simplemente necesitamos que las herramientas de compilación impriman el desplazamiento en el sistema utilizado para compilar, no específicamente el compilador.

En este caso, GCC y Clang tienen la capacidad de incluir texto arbitrario en su salida de ensamblaje e incluir varios operandos de datos en ese texto, incluidos valores inmediatos para compensaciones de estructura.

Dentro de cualquier función, incluya estas líneas:

 #if GenerateStructureOffsets __asm__("# offsetof(struct A, b) = %c0" : : "i" (offsetof(struct A, b))); #endif

Luego compila con los modificadores -DGenerateStructureOffsets y -S . El compilador generará un archivo llamado SourceFileName .s , y puede usar -o Name para darle un nombre diferente si lo desea.

Luego, grep "## offsetof" Name encontrará esta línea, mostrando algo como:

    ## compensación de (estructura A, b) = 1

Luego puede usar sed u otras herramientas para extraer el valor.

En el __asm__ , "i" dice que se genere un operando "inmediato". El (offsetof(struct A, b)) que sigue que da el valor que debería tener. En la primera cadena entre comillas, %c0 se reemplaza con el valor de ese operando.

El 0 indica qué operando reemplazar; si hubo más de uno enumerado más adelante en el __asm__ , se numeran 0, 1, 2, 3, etc. (También hay un mecanismo para nombrarlos en lugar de numerarlos, que no se muestra aquí). Normalmente, %0 se reemplazaría por la forma de operando inmediato adecuado para el lenguaje ensamblador de destino, como $1 o #1 . Sin embargo, el modificador c dice que use la constante simple, por lo que el texto de reemplazo es solo el valor, en este caso 1 .

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda