¿Printf (“% x”, 1) invoca un comportamiento indefinido?

De acuerdo con el estándar C (6.5.2.2 párrafo 6)

Si la expresión que denota la función llamada tiene un tipo que no incluye un prototipo, las promociones enteras se llevan a cabo en cada argumento, y los argumentos que tienen tipo flotante se promueven en el doble. Estas se llaman promociones de argumento predeterminadas. Si el número de argumentos no es igual al número de parámetros, el comportamiento es indefinido. Si la función se define con un tipo que incluye un prototipo, y el prototipo termina con puntos suspensivos (, …) o los tipos de argumentos después de la promoción no son compatibles con los tipos de los parámetros, el comportamiento no está definido. Si la función se define con un tipo que no incluye un prototipo y los tipos de argumentos después de la promoción no son compatibles con los de los parámetros posteriores a la promoción, el comportamiento no está definido, excepto en los siguientes casos:

  • un tipo promovido es un tipo entero con signo, el otro tipo promovido es el tipo entero sin signo correspondiente, y el valor es representable en ambos tipos;
  • ambos tipos son punteros a versiones calificadas o no calificadas de un tipo de personaje o nulo.

Por lo tanto, en general, no hay nada de malo en pasar un int a una función variadic que espera un unsigned int (o viceversa) siempre que el valor pasado se ajuste en ambos tipos. Sin embargo, la especificación para lecturas de printf (7.19.6.1 párrafo 9):

Si una especificación de conversión no es válida, el comportamiento no está definido. Si algún argumento no es del tipo correcto para la especificación de conversión correspondiente, el comportamiento es indefinido.

No se hacen excepciones para la discrepancia entre firma / no firmada.

¿Esto significa que printf("%x", 1) invoca un comportamiento indefinido?

Creo que no está definido técnicamente, porque el “tipo correcto” para %x se especifica como unsigned int , y como usted señala, aquí no hay ninguna excepción para la falta de coincidencia con signo / sin signo.

Las reglas para printf son para un caso más específico y así anulan las reglas para el caso general (para otro ejemplo de la anulación específica del general, es permisible en general pasar NULL a una función esperando un argumento const char * , pero no está definido comportamiento para pasar NULL a strlen() ).

Digo “técnicamente”, porque creo que una implementación debería ser intencionalmente perversa para causar un problema en este caso, dadas las otras restricciones en el estándar.

No, porque% x formatea un int sin signo, y el tipo de la expresión constante 1 es int, mientras que el valor del mismo se puede express como un int sin signo. La operación no es UB.

Es un comportamiento indefinido, por la misma razón que la reinterpretación de un puntero a un tipo entero a un tipo complementario de signatura opuesta. Esto no está permitido, desafortunadamente, en ambas direcciones porque una representación válida en uno puede ser una implementación de trampa en el otro.

La única razón por la que veo que desde la reinterpretación firmada a la sin firmar puede haber una representación de trampa es este caso pervertido de representación de signos donde el tipo sin signo simplemente enmascara el bit de signo. Lamentablemente, tal cosa está permitida a partir de 6.2.6.2 del estándar. En dicha architecture, todos los valores negativos del tipo firmado pueden ser representaciones de trampa del tipo sin signo.

En el caso de ejemplo, esto es aún más extraño, ya que tener 1 una representación de trampa para el tipo sin firmar no está permitido. Entonces, para que sea un ejemplo “real”, tendría que hacer su pregunta con un -1 .

No creo que haya todavía ninguna architecture para la cual las personas escriban comstackdores de C que tengan estas características, por lo que definitivamente sería más fácil si una versión más nueva de la norma pudiera abolir este desagradable caso.

Creo que no está definido. Las funciones con una lista de argumentos de longitud variable no tienen una conversión implícita cuando se aceptan argumentos, por lo que 1 no se lanzará a unsigned int cuando esté pasado a printf() , lo que provocará un comportamiento indefinido.

Los autores del Estándar generalmente no intentan ordenar explícitamente el comportamiento en cada caso de esquina imaginable, especialmente cuando existe un comportamiento correcto obvio que es compartido por el 100% de todas las implementaciones, y no hay ninguna razón para esperar que ninguna implementación haga otra cosa. A pesar del requisito explícito del Estándar de que los tipos con y sin firma tengan representaciones de memoria coincidentes para valores que se ajusten a ambos, sería teóricamente posible que una implementación las pasara a las funciones variadic de forma diferente. El Estándar no prohíbe tal comportamiento, pero no veo evidencia de que los autores lo permitan intencionalmente. Lo más probable es que simplemente no consideraran esa posibilidad ya que ninguna implementación (por lo que yo sé, alguna vez) había funcionado de esa manera.

Probablemente sería razonable que una implementación desinfectante graznara si el código usa% x en un valor firmado, aunque una implementación de sanitización de calidad también debería proporcionar una opción para aceptar silenciosamente dicho código. No hay ninguna razón para que las implementaciones en buenas condiciones hagan otra cosa que no sea procesar el valor pasado como unsigned o squawk si se usa en un modo de diagnóstico / desinfección. Si bien el Estándar podría prohibir que una implementación considere inalcanzable cualquier código que use% x en un valor firmado, cualquiera que piense que las implementaciones deberían hacer uso de dicha libertad debería ser reconocido como un imbécil.

Los progtwigdores que se dirigen exclusivamente a implementaciones no diagnósticas sanas no deberían tener que preocuparse por agregar moldes cuando emiten valores como “uint8_t”, pero aquellos cuyo código podría ser alimentado a implementaciones morónicas podrían querer agregar tales conversiones para evitar comstackdores del ” optimizaciones “tales implementaciones podrían imponer.