2013-12-05 2 views
-3

Я пришел к этому question и увидеть эту линиюIs printf (c); является допустимым синтаксисом (где c - строковый литерал)?

printf(&c[i]); 

Я хочу знать, что это действительный синтаксис? Печать строкового/строкового литерала без спецификатора формата %s не вызывает неопределенное поведение или нарушение ограничений?
И если это допустимый синтаксис, то в какой цели он используется?

Я составил этот код

#include <stdio.h> 

int main() 
{ 
    char *c = "Hello World"; 

    printf(c); 
    printf("\n\n"); 
    printf(&c[0]); 

    return 0; 
} 

и компилирует без предоставления каких-либо предупреждение/ошибка с выходом

Hello World 

Hello World 
+1

Какой компилятор вы используете, не выдавая предупреждений при просмотре этого кода? – devnull

+1

@devnull; GCC 4.8.1, скомпилированный с флагом 'pedantic',' Wextra', 'Wall' в режиме C99. – haccks

+1

GCC 4.4.3 с опцией -wall дает предупреждение: формат не строковый литерал и аргументы формата –

ответ

3

Это неразумно (особенно, если указанная строка пришла от пользователя), но это не является незаконным ,

Предложение в вопросе будет раздел 7.19.6.1, пункт 3 (курсив мой):

Формат должен быть многобайтовая последовательность символов, начиная и заканчивая в исходное состояние сдвига. Формат состоит из ноль или более директив: обычные многобайтовые символы (не%), которые копируются без изменений в выходной поток; и спецификации преобразования, каждый из которых приводит к извлечению нулевых или более последующих аргументов, преобразуя их, если применимо, в соответствии с соответствующим спецификатором преобразования, а затем записывая результат в выходной поток.

Вы должны либо использовать fputs(c); или fprintf("%s", c);, чтобы убедиться, что ваша строка не случайно интерпретировано содержит директивы.

0

Это разрешено, но это рискованно. Рассмотрим некоторые функции, как показано ниже.

void foo(const char* s) { 
    printf(s); 
} 

Это может генерировать ядро, если что-то вроде %s находится во входном аргументе.

1

Это работает, но не рекомендуется. Предположим, что у вас

char *c = "We have a 30%sale!"; 

Тогда ваши printf заявления будут получать доступ к мусорный памяти пытается решить %s.

+0

Я отредактировал ваш ответ в соответствии с моим редактированием. – haccks

1

Использование printf является ярким примером небезопасного кода: Правильность вашей программы не может быть определена из исходного кода (и в частности, типа система) в одиночку; правильность зависит от значения, а не типы. Тот факт, что такой код возможен, делает C «небезопасным языком». Пример:

void f(char const * p) 
{ 
    printf("%s", p);  // this is safe! 

    printf(p);   // correct if the string contains no format specifiers; 
          // undefined behaviour otherwise 
} 

Повторить: правильность вашей программы зависит от ее характеристик времени выполнения и не может быть гарантирована статически.

Вы никогда не должны писать такой код!

+0

Kerrek, я поразился, что это разрешено в C! Я думаю, что это дыра в петле. – haccks

+3

@haccks: Серьезно? C является * полным * таких вещей ... –

+0

@haccks: loop hole? В C вы можете делать в основном все, что хотите, и это по дизайну. То, что нельзя сделать, просто потому, что компилятор не понимает, какие операции вы хотите делать, а не потому, что он не хочет, чтобы вы что-то делали. – 6502

0

Это работает, потому что c является указателем на начало строки (другими словами, это указатель на первый знак вашей строки). c[0] позволяет вам получить W. И & давайте укажем на это char. Конструкция, которую вы использовали в коде, просто получает значение по указателю и сразу же возвращает указатель этого значения. Например, c[i] равно *(c+i).

Почему это работает? Поскольку функция printf() получает указатель на строку в качестве аргумента. И он печатает все значки, начиная с указателя до знака '\0'.

Пожалуйста, узнайте больше о указателях на языке C и о том, как реализованы C-массивы и C-строка.

+0

Я изучаю указатели, массивы и строку и их реализации, и именно поэтому я спросил. :) – haccks

+0

@haccks Итак, добро пожаловать! Надеюсь, мой ответ вам помог :). –

Смежные вопросы