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

151
Visualizações
¿La inicialización idiomática de una matriz dinámica invoca un comportamiento indefinido?

Esta pregunta puede ser un poco controvertida. Tengo el siguiente código en el alcance del bloque:

 int *a = malloc(3 * sizeof(int)); if (!a) { ... error handling ... } a[0] = 0; a[1] = 1; a[2] = 2;

Argumento que este código invoca UB debido a la aritmética de punteros fuera de los límites. La razón es que el tipo efectivo del puntero de objeto por a nunca se establece en int[3] sino solo en int . Por lo tanto, cualquier acceso al objeto en un índice distinto de 0 no está definido por el estándar C.

He aquí por qué:

Línea a = malloc(...) . Si la asignación tiene éxito, entonces se asignan puntos a a región lo suficientemente grande como para almacenar 3 int s.

a[0] = ... es equivalente a *a = ... , un valor l de int . Establece el tipo efectivo de los primeros bytes sizeof(int) en int como se indica en la regla 6.5p6 .

... Para todos los demás accesos a un objeto que no tiene un tipo declarado, el tipo efectivo del objeto es simplemente el tipo del lvalue utilizado para el acceso.

Ahora el puntero a apunta a un objeto de tipo int , no int[3] .

a[1] = ... es equivalente a *(a + 1) = . La expresión a + 1 apunta a un elemento uno después del final del objeto int accesible a través *a . Este puntero en sí mismo es válido para la comparación, pero el acceso no está definido debido a:

Regla 6.5.6p7 :

... un puntero a un objeto que no es un elemento de una matriz se comporta igual que un puntero al primer elemento de una matriz de longitud uno con el tipo del objeto como su tipo de elemento.

Y la regla 6.5.6p8 :

... Si el resultado apunta uno más allá del último elemento del objeto de matriz, no se utilizará como operando de un operador * unario que se evalúa.

El problema similar es relevante para a[2] = ... pero aquí incluso a + 2 oculto en a[2] invoca UB .

El problema podría resolverse si el estándar permitiera la aritmética de punteros arbitrarios con la región válida de la memoria siempre que se cumplan los requisitos de alineación y la estricta regla de aliasing. O que cualquier colección de objetos consecutivos del mismo tipo puede tratarse como una matriz. Sin embargo, no pude encontrar tal cosa.

Si mi interpretación del estándar es correcta, entonces algún código C (¿todo?) No estaría definido. Por lo tanto, es uno de esos raros casos en los que espero estar equivocado .

¿Soy yo?

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

0

El Estándar sólo define "a medias" el término "objeto": dice que todo objeto es una región de almacenamiento, pero no especifica cuándo una región de almacenamiento es o no un objeto. Para la mayor parte del Estándar, estaría bien decir que cada región de almacenamiento contiene simultáneamente todos los objetos de todos los tipos que caben allí; cualquier acción que modifique un objeto modifica el almacenamiento subyacente, y cualquier acción que modifique el almacenamiento subyacente modifica el valor almacenado de todos los objetos en él.

Creo que está bastante claro que los autores del estándar esperaban que en los casos en que el estándar dice que una acción invoca un comportamiento indefinido, pero el comportamiento se definiría en ausencia de esa declaración, las implementaciones de calidad deberían comportarse de la manera definida en los casos en que su los clientes lo encontrarían útil . Sin embargo, la cuestión de cuáles son esos casos es un problema de Calidad de Implementación fuera de la jurisdicción de la Norma. Como tal, realmente no importaba si el Estándar caracterizaba como Comportamiento indefinido alguna acción que todas las implementaciones hasta la fecha habían procesado de la misma manera obviamente útil, porque nadie que pretendiera vender compiladores interpretaría el hecho de que el Estándar no ordenó tal comportamiento como una invitación a desviarse de él en formas que serían perjudiciales para sus clientes.

Debido a que se usan diferentes compiladores para diferentes propósitos, la única forma en que el Estándar podría definir todos los comportamientos que serían necesarios para muchas tareas de programación de bajo nivel y al mismo tiempo permitir todas las optimizaciones que serían útiles para el procesamiento de números de alto nivel sería para reconocer categorías de implementaciones que realizan diferentes optimizaciones, o agregar mejores medios para invitar o bloquear optimizaciones que mejorarían el rendimiento y/o darían como resultado un comportamiento incorrecto del programa. Debido a que todos los compiladores que han existido alguna vez o existirán plausiblemente alguna vez se abstendrán de realizar algunas optimizaciones que de otro modo habrían sido útiles, y/o realizarán "optimizaciones" que procesan incorrectamente algunos programas C11 estrictamente conformes, la cuestión de si el Estándar permitiría una La optimización tonta solo debería ser relevante para las personas que desean escribir compiladores de baja calidad o que desean esforzarse al máximo para ser compatibles con ellos.

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