Могу ли я использовать scanf для захвата директивы с шириной, заданной переменной?

У меня есть следующий код:

scanf(" %Xs %Ys", buf1, buf2);

Где X и Y должны быть целыми числами. Проблема в том, что значения для X и Y являются константами времени компиляции, и даже если бы я хотел жестко закодировать значения в строку формата, я не могу, потому что я не знаю значений. В printf вы можете отправить переменную ширины вместе с аргументами с помощью «%*s». Есть ли аналог для scanf?

РЕДАКТИРОВАТЬ: Чтобы уточнить, константы известны во время компиляции, но не во время кодирования, и вообще не мной. Они могут различаться в зависимости от платформы или реализации, и они могут измениться после того, как я закончу. Даже если бы они этого не сделали, я все равно не хотел бы, чтобы размеры буфера дублировались в строках формата, готовые к segfault в ту минуту, когда я забуду их синхронизировать.


person Thom Smith    schedule 11.10.2009    source источник
comment
Константы времени компиляции известны во время компиляции, не так ли, поэтому значения могут быть встроены в строку? Но затем вы говорите, что не знаете значений, поэтому не можете их закодировать... Вопрос кажется противоречивым.   -  person Jonathan Leffler    schedule 11.10.2009
comment
Как вы, вероятно, знаете, '' в scanf() означает подавление любого присвоения для этого значения. Ничего похожего на '' в printf() для scanf() нет. Керниган и Пайк делают то, что предлагает @sambowry в «Практике программирования».   -  person Jonathan Leffler    schedule 11.10.2009


Ответы (3)


Вы можете создать строку формата с помощью sprintf():

sprintf( format, " %%%is %%%is", X, Y );
scanf(format, buf1, buf2);

РЕДАКТИРОВАТЬ: удивительно, но работает следующий код gcc:

#include <stdio.h> 

#define LIST(...) __VA_ARGS__ 

#define scanf_param( fmt, param, str, args ) {  \ 
  char fmt2[100]; \ 
  sprintf( fmt2, fmt, LIST param ); \ 
  sscanf( str, fmt2, LIST args  ); \ 
} 

enum { X=3 };
#define Y X+1 

int main(){
  char str1[10], str2[10];

  scanf_param( " %%%is %%%is", (X,Y), " 123 4567", (&str1, &str2) );

  printf("str1: '%s'   str2: '%s'\n", str1, str2 );
}
person sambowry    schedule 11.10.2009
comment
Пустая трата ресурсов времени выполнения, если числа являются константами, вам так не кажется? - person LiraNuna; 11.10.2009
comment
Верно, но более гибко. Он работает, когда X и Y читают из файла и т. д. - person sambowry; 11.10.2009
comment
@LIraNuna: Нет, это не пустая трата ресурсов времени выполнения (поскольку в одной части вопроса говорится о значениях, неизвестных во время компиляции, а в другой части говорится, что значения являются константами времени компиляции). Именно так Керниган и Пайк решают проблему в «Практике программирования», потому что нет простой и надежной альтернативы. - person Jonathan Leffler; 11.10.2009
comment
Я думаю, вам нужно изменить LIST param на LIST(param) - любой компилятор, принимающий первую форму, неверен и нуждается в исправлении. - person Chris Lutz; 11.10.2009
comment
@Chris: «параметр» содержит необходимые скобки. [ 'LIST param' --› 'LIST (X,Y)' --› 'X,Y' ] - person sambowry; 11.10.2009

Проблема в том, что значения X и Y являются константами времени компиляции.

Затем используйте функцию вставки макроса:

#include <stdio.h>

#define TEST 2

#define CONST_TO_STRING_(x) #x
#define CONST_TO_STRING(x) CONST_TO_STRING_(x)

int main() {
    printf("1 " CONST_TO_STRING(TEST) " 3\n");
    return 0;
}
person LiraNuna    schedule 11.10.2009
comment
Это не сработает, если константы времени компиляции определены как что-то отличное от простого целого числа без прикрас, например, sizeof foo, 10 * 2, 500UL, 0x20 и '\n' все потерпят неудачу. - person caf; 11.10.2009
comment
ОП не сказал, как объявляются эти константы. Если это не его/ее случай, вопрос следует отредактировать. - person LiraNuna; 11.10.2009
comment
ОП сказал, что это константы времени компиляции, термин, который охватывает все константы в моих примерах. - person caf; 11.10.2009

Ваш вопрос не ясен. Если вы не знаете значений, то они, вероятно, являются константами времени выполнения, а не константами времени компиляции.

Если это так (т. е. они являются константами времени выполнения), то нет, в 'scanf' такой функции нет. Единственное, что вы можете сделать, это создать полную строку формата (со встроенными в нее конкретными значениями) во время выполнения с помощью 'sprintf', а затем передать эту строку формата вашему 'scanf'.

person AnT    schedule 11.10.2009
comment
Легко могут быть неизвестные константы времени компиляции - когда-нибудь слышали о #ifdef ? - person Chris Lutz; 11.10.2009
comment
Ну, когда я говорю неизвестно, я имею в виду неизвестность компилятору во время компиляции, потому что, на мой взгляд, это единственная подходящая форма неизвестного. Константы манифеста #define, известные во время компиляции, могут быть встроены в строку формата препроцессором (уже ответили здесь). - person AnT; 11.10.2009