Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

251
Visualizações
¿Por qué el compilador de C no puede optimizar el cambio del valor de un puntero const asumiendo que dos punteros a la misma variable serían ilegales/UB?

Recientemente me topé con una comparación entre Rust y C y usan el siguiente código:

 bool f(int* a, const int* b) { *a = 2; int ret = *b; *a = 3; return ret != 0; }

En Rust (mismo código, pero con la sintaxis de Rust), produce el siguiente código ensamblador:

 cmp dword ptr [rsi], 0 mov dword ptr [rdi], 3 setne al ret

Mientras que con gcc produce lo siguiente:

 mov DWORD PTR [rdi], 2 mov eax, DWORD PTR [rsi] mov DWORD PTR [rdi], 3 test eax, eax setne al ret

El texto afirma que la función C no puede optimizar la primera línea porque a y b podrían apuntar al mismo número. En Rust esto no está permitido, por lo que el compilador puede optimizarlo.

Ahora a mi pregunta:

La función toma un const int* que es un puntero a un const int . Leí esta pregunta y dice que modificar un const int con un puntero debería dar como resultado una advertencia del compilador y el peor lanzamiento en UB.

¿Podría esta función dar como resultado un UB si lo llamo con dos punteros al mismo entero?

¿Por qué el compilador de C no puede optimizar la primera línea, suponiendo que dos punteros a la misma variable serían ilegales/UB?

Enlace a Godbolt

over 4 years ago · Santiago Trujillo
5 Respostas
Responde à pergunta

0

La función toma una const int* que es un puntero a una const int.

No, const int* no es un puntero a const int . Cualquiera que diga eso se engaña.

  • int* es un puntero a un int que definitivamente no es const.

  • const int* es un puntero a un int de constancia desconocida.

  • No hay forma de expresar la noción de un puntero a un int que definitivamente es const.

Si C fuera un lenguaje mejor diseñado, entonces const int * sería un puntero a un const int, mutable int * (tomando prestada una palabra clave de C++) sería un puntero a un no const int e int * sería un puntero a un int de constancia desconocida. Eliminar los calificadores (es decir, olvidar algo sobre el tipo apuntado) sería seguro, lo contrario de C real en el que agregar el calificador const es seguro. No he usado Rust, pero parece de ejemplos en otra respuesta que usa una sintaxis como esa.

Bjarne Stroustrup, quien introdujo const , originalmente lo llamó readonly , que se acerca mucho más a su significado real. int readonly* habría dejado más claro que es el puntero el que es de solo lectura, no el objeto apuntado. El cambio de nombre a const ha confundido a generaciones de programadores.

Cuando tengo la opción, siempre escribo foo const* , no const foo* , como la mejor opción después de readonly* .

over 4 years ago · Santiago Trujillo Relatório

0

Cabe señalar que esta pregunta se refiere a la optimización en -Ofast y cómo es incluso el caso allí.

Esencialmente, el compilador C de la función no conoce el conjunto discreto completo de direcciones que se le pueden pasar, ya que no se conoce hasta el momento del enlace/tiempo de ejecución, ya que se puede llamar a la función desde varias unidades de traducción y, por lo tanto, tiene en cuenta que manejan cualquier dirección legal a la que a y b puedan apuntar, y por supuesto eso incluye el caso en el que se superponen.

Por lo tanto, debe usar restrict para indicarle que actualizar a (que la función permite porque no es un puntero a constante, pero incluso entonces la función podría descartar const) no actualiza el valor al que apunta b , que debe incluirse en la comparación con 0, por lo tanto, la tienda a que sucede antes de que la comparación deba continuar, mientras que en rust la suposición predeterminada es restricta. Sin embargo, el compilador de la función sabe que *a es lo mismo que *(a+1-1) y, por lo tanto, no producirá 2 tiendas separadas, pero no sabe si a o b se superponen.

over 4 years ago · Santiago Trujillo Relatório

0

¿Por qué el Compilador de C no puede optimizar la primera línea, suponiendo que dos punteros a la misma variable serían ilegales/UB?

Debido a que no le ha indicado al compilador de C que lo haga, se le permite hacer esa suposición.

C tiene un calificador de tipo para exactamente esto llamado restrict que significa más o menos: este puntero no se superpone con otros punteros (no exactamente , pero sigue el juego).

La salida del ensamblaje para

 bool f(int* restrict a, const int* b) { *a = 2; int ret = *b; *a = 3; return ret != 0; }

es

 mov eax, DWORD PTR [rsi] mov DWORD PTR [rdi], 3 test eax, eax setne al ret

... que elimina/optimiza la asignación *a = 2

De https://en.wikipedia.org/wiki/Restrict

En el lenguaje de programación C, restrict es una palabra clave que se puede usar en declaraciones de puntero. Al agregar este calificador de tipo, un programador sugiere al compilador que durante la vida útil del puntero, solo se usará el puntero en sí o un valor directamente derivado de él (como puntero + 1) para acceder al objeto al que apunta.

over 4 years ago · Santiago Trujillo Relatório

0

La función int f(int *a, const int *b); promete no cambiar el contenido de b a través de ese puntero ... No promete nada con respecto al acceso a las variables a través del puntero a .

Si a y b apuntan al mismo objeto, cambiarlo a través a es legal (siempre que el objeto subyacente sea modificable, por supuesto).

Ejemplo:

 int val = 0; f(&val, &val);
over 4 years ago · Santiago Trujillo Relatório

0

Si bien las otras respuestas mencionan el lado C, aún vale la pena echar un vistazo al lado Rust. Con Rust, el código que tienes es probablemente este:

 fn f(a:&mut i32, b:&i32)->bool{ *a = 2; let ret = *b; *a = 3; return ret != 0; }

La función acepta dos referencias, una mutable y otra no. Las referencias son punteros que se garantiza que son válidos para lecturas, y también se garantiza que las referencias mutables son únicas, por lo que se optimizan para

 cmp dword ptr [rsi], 0 mov dword ptr [rdi], 3 setne al ret

Sin embargo, Rust también tiene punteros en bruto que son equivalentes a los punteros de C y no ofrecen tales garantías. La siguiente función, que toma punteros sin procesar:

 unsafe fn g(a:*mut i32, b:*const i32)->bool{ *a = 2; let ret = *b; *a = 3; return ret != 0; }

pierde la optimización y compila a esto:

 mov dword ptr [rdi], 2 cmp dword ptr [rsi], 0 mov dword ptr [rdi], 3 setne al ret

Enlace de Godbolt

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda